<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Uvicorn blog</title><link>https://uvicorn.github.io/</link><description>Recent content on Uvicorn blog</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Thu, 17 Aug 2023 05:00:00 +0700</lastBuildDate><atom:link href="https://uvicorn.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>CTFZone23 - Messenger.zone Writeup</title><link>https://uvicorn.github.io/posts/ctfzone23-messenger.zone/</link><pubDate>Thu, 17 Aug 2023 05:00:00 +0700</pubDate><guid>https://uvicorn.github.io/posts/ctfzone23-messenger.zone/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/ctfzone23-messenger.zone/ -&lt;h1 id="messengerzone-4-solves">Messenger.zone (4 solves)&lt;/h1>
&lt;p>At this ctf we took the third place&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/SJBpm0vnh.png" alt="">&lt;/p>
&lt;p>Actually Messenger.zone wasn&amp;rsquo;t difficult crypto, just difficult exploitation challenge. I don&amp;rsquo;t have any english words to describe exploitation, but in russian it sounds like &amp;ldquo;через три пизды&amp;rdquo;.&lt;/p>
&lt;h2 id="introduction">Introduction&lt;/h2>
&lt;p>&lt;a href="https://github.com/uvicorn/writeups/tree/master/ctfzone23%20-%20messager.zone">Source code&lt;/a> and task description:&lt;/p>
&lt;blockquote>
&lt;p>We developed secure messenger based on signal specification. We also used only secure analogs of known algorithms. But our comminications has been compromised. An attacker was able to intercepted the message with flag (flag.pcapng). He knows that it was 8th message between clients and they had started chat about 1 min before intercepted message. Can he decrypt the flag?&lt;/p>
&lt;/blockquote>
&lt;p>We got 8th message between clients:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-http" data-lang="http">&lt;span style="color:#a6e22e">POST&lt;/span> /send &lt;span style="color:#66d9ef">HTTP&lt;/span>&lt;span style="color:#f92672">/&lt;/span>&lt;span style="color:#ae81ff">1.1&lt;/span>
Host&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">localhost:7777&lt;/span>
User-Agent&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">python-requests/2.31.0&lt;/span>
Accept-Encoding&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">gzip, deflate&lt;/span>
Accept&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">*/*&lt;/span>
Connection&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">keep-alive&lt;/span>
Content-Length&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">531&lt;/span>
Content-Type&lt;span style="color:#f92672">:&lt;/span> &lt;span style="color:#ae81ff">application/json&lt;/span>
{
&lt;span style="color:#f92672">&amp;#34;from_m&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;B&amp;#34;&lt;/span>,
&lt;span style="color:#f92672">&amp;#34;to_m&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;A&amp;#34;&lt;/span>,
&lt;span style="color:#f92672">&amp;#34;header&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;10007557092155308918620703319005578742802155531542215927047486636897385017421026687658302411228112816312151375158019561914808361055666669789420151300043193;6987718573966126734765996266581284255829614508168823941052245373167186664467200288000376804417263861590165057549101655594459771412333345116018563168510146;1;0&amp;#34;&lt;/span>,
&lt;span style="color:#f92672">&amp;#34;message&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;b3f3ca9e16fc1c33c86bb08e9ecee860462cdd6716dd2c32a6701b978c76035ec2973e2c6eac490d54f7918a0167179037459cbda47e4abcd5028a405d8374ada62fd23e3fcb29ab1e36e44ef7cfa438&amp;#34;&lt;/span>
}
&lt;span style="color:#960050;background-color:#1e0010">HTTP/&lt;/span>&lt;span style="color:#ae81ff">1.1&lt;/span> &lt;span style="color:#ae81ff">201&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">Created&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">Server:&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">TornadoServer/&lt;/span>&lt;span style="color:#ae81ff">6.1&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">Content-Type:&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">application/json;&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">charset=UTF&lt;/span>&lt;span style="color:#ae81ff">-8&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">Date:&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">Sun,&lt;/span> &lt;span style="color:#ae81ff">16&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">Jul&lt;/span> &lt;span style="color:#ae81ff">2023&lt;/span> &lt;span style="color:#ae81ff">21&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">53&lt;/span>&lt;span style="color:#960050;background-color:#1e0010">:&lt;/span>&lt;span style="color:#ae81ff">34&lt;/span> &lt;span style="color:#960050;background-color:#1e0010">GMT&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">Content-Length:&lt;/span> &lt;span style="color:#ae81ff">33&lt;/span>
{&lt;span style="color:#f92672">&amp;#34;message&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;Save msg on server&amp;#34;&lt;/span>}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>we have basic client-server messenger and 2 clients A and B:&lt;/p>
&lt;pre tabindex="0">&lt;code>Client: B
1 - Change client
2 - Send msg
3 - Pull msgs
q - quit
&amp;gt;
&lt;/code>&lt;/pre>&lt;h2 id="initial-analysis">Initial analysis&lt;/h2>
&lt;p>Server side is just database logic that is not interesting for us. If we look at client we can see 400 lines of code with some strange crypto GOSTs(russian state standard):&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/rkcSEYwnh.png" alt="">&lt;/p>
&lt;p>Scared? Me too.
But with detailed review we can see that most of this code its just bullshit.&lt;/p>
&lt;p>First thing we need to notice - usage of &lt;code>random.seed&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">size&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">64&lt;/span>
start_time &lt;span style="color:#f92672">=&lt;/span> int(time&lt;span style="color:#f92672">.&lt;/span>time())
random&lt;span style="color:#f92672">.&lt;/span>seed(start_time)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate_bytes&lt;/span>(n&lt;span style="color:#f92672">=&lt;/span>size):
&lt;span style="color:#66d9ef">return&lt;/span> random&lt;span style="color:#f92672">.&lt;/span>randbytes(n)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>If we set start_time to some constant and run, then we can see all generated parameters are the same. I ran 2 instances and sent messages &amp;ldquo;avtor_ti_cho_tvorish???&amp;rdquo; and &amp;ldquo;eto rofls&amp;rdquo; with &lt;code>start_time=1337&lt;/code>:
&lt;img src="https://uvicorn.github.io/images/r1aEl5D23.png" alt="">
As you can see headers are the same, but encrypted messages aren&amp;rsquo;t.&lt;/p>
&lt;p>Lets look at header generation:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Server&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">store_message&lt;/span>(self, from_m, to_m, header, message):
print(&lt;span style="color:#e6db74">&amp;#39;Save msg on server&amp;#39;&lt;/span>)
print(&lt;span style="color:#e6db74">&amp;#39;To:&amp;#39;&lt;/span>,to_m)
print(&lt;span style="color:#e6db74">&amp;#39;From:&amp;#39;&lt;/span>,from_m)
print(&lt;span style="color:#e6db74">&amp;#39;header:&amp;#39;&lt;/span>,header)
print(&lt;span style="color:#e6db74">&amp;#39;message:&amp;#39;&lt;/span>,message)
data &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#e6db74">&amp;#39;from_m&amp;#39;&lt;/span>:from_m, &lt;span style="color:#e6db74">&amp;#39;to_m&amp;#39;&lt;/span>:to_m, &lt;span style="color:#e6db74">&amp;#39;header&amp;#39;&lt;/span>: header_to_string(header), &lt;span style="color:#e6db74">&amp;#39;message&amp;#39;&lt;/span>:message&lt;span style="color:#f92672">.&lt;/span>hex()}
print(data)
r &lt;span style="color:#f92672">=&lt;/span> requests&lt;span style="color:#f92672">.&lt;/span>post(server_url&lt;span style="color:#f92672">+&lt;/span>send_api, json&lt;span style="color:#f92672">=&lt;/span>data)
print(r&lt;span style="color:#f92672">.&lt;/span>json())
&lt;span style="color:#66d9ef">return&lt;/span> r&lt;span style="color:#f92672">.&lt;/span>json()[&lt;span style="color:#e6db74">&amp;#39;message&amp;#39;&lt;/span>] &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;Save msg on server&amp;#39;&lt;/span>
&lt;span style="color:#75715e"># by XREFs on store_message we can find this:&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Client&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> __init__(self, &lt;span style="color:#f92672">...&lt;/span>):
&lt;span style="color:#f92672">...&lt;/span>
self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict &lt;span style="color:#f92672">=&lt;/span> dict()
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send&lt;/span>(self, m_to, msg, send&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> m_to &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#f92672">in&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict&lt;span style="color:#f92672">.&lt;/span>keys():
self&lt;span style="color:#f92672">.&lt;/span>start_x3dh(m_to)
msg &lt;span style="color:#f92672">=&lt;/span> pad2(msg, block_size)
AD &lt;span style="color:#f92672">=&lt;/span> (self&lt;span style="color:#f92672">.&lt;/span>name &lt;span style="color:#f92672">+&lt;/span> m_to)&lt;span style="color:#f92672">.&lt;/span>encode(&lt;span style="color:#e6db74">&amp;#39;utf-8&amp;#39;&lt;/span>)
head, cipher &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict[m_to]&lt;span style="color:#f92672">.&lt;/span>RatchetEncrypt(msg, AD)
&lt;span style="color:#66d9ef">if&lt;/span> send:
print(&lt;span style="color:#e6db74">&amp;#39;SEND&amp;#39;&lt;/span>, header_to_string(head)&lt;span style="color:#f92672">.&lt;/span>encode(&lt;span style="color:#e6db74">&amp;#39;utf-8&amp;#39;&lt;/span>), cipher, AD)
self&lt;span style="color:#f92672">.&lt;/span>server&lt;span style="color:#f92672">.&lt;/span>store_message(self&lt;span style="color:#f92672">.&lt;/span>name, m_to, head, cipher)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>
&lt;span style="color:#75715e"># found by XREFs on RatchetEncrypt&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Ratchet&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">RatchetEncrypt&lt;/span>(self, plaintext, AD):
self&lt;span style="color:#f92672">.&lt;/span>CKs, mk &lt;span style="color:#f92672">=&lt;/span> KDF_CK(self&lt;span style="color:#f92672">.&lt;/span>CKs)
header &lt;span style="color:#f92672">=&lt;/span> HEADER(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>PN, self&lt;span style="color:#f92672">.&lt;/span>Ns)
self&lt;span style="color:#f92672">.&lt;/span>Ns &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#75715e"># Number of Sended messages&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> header, ENCRYPT(mk, plaintext, CONCAT(AD, header))
&lt;span style="color:#75715e"># client.send -&amp;gt; server.store_message&lt;/span>
&lt;span style="color:#75715e"># client.send(msg) -&amp;gt; RatchetEncrypt(msg) which uses header&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>On this moment we have pseudocode of send_msg function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict &lt;span style="color:#f92672">=&lt;/span> {}
&lt;span style="color:#75715e"># doing some things with RATCHET_dict&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_msg&lt;/span>(msg,from_m, to_m):
head, cipher &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict[m_to]&lt;span style="color:#f92672">.&lt;/span>RatchetEncrypt(msg)
&lt;span style="color:#66d9ef">return&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;header&amp;#34;&lt;/span>: header_to_string(head), &lt;span style="color:#e6db74">&amp;#34;msg&amp;#34;&lt;/span>: cipher, &lt;span style="color:#f92672">...&lt;/span>}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Lets check header_to_string realization:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">header_to_string&lt;/span>(header):
print([header&lt;span style="color:#f92672">.&lt;/span>dh, header&lt;span style="color:#f92672">.&lt;/span>pn, header&lt;span style="color:#f92672">.&lt;/span>n])
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#39;;&amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>join([str(header&lt;span style="color:#f92672">.&lt;/span>dh[&lt;span style="color:#ae81ff">0&lt;/span>]), str(header&lt;span style="color:#f92672">.&lt;/span>dh[&lt;span style="color:#ae81ff">1&lt;/span>]), str(header&lt;span style="color:#f92672">.&lt;/span>pn), str(header&lt;span style="color:#f92672">.&lt;/span>n)])
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">HEADER&lt;/span>(dh_pair, pn, n):
a &lt;span style="color:#f92672">=&lt;/span> Header()
a&lt;span style="color:#f92672">.&lt;/span>dh &lt;span style="color:#f92672">=&lt;/span> dh_pair[&lt;span style="color:#ae81ff">1&lt;/span>]
a&lt;span style="color:#f92672">.&lt;/span>pn &lt;span style="color:#f92672">=&lt;/span> pn
a&lt;span style="color:#f92672">.&lt;/span>n &lt;span style="color:#f92672">=&lt;/span> n
&lt;span style="color:#66d9ef">return&lt;/span> a
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Header&lt;/span>(object):
&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Lets look at header&amp;rsquo;s format &lt;code>376876138...04158;666457945261308...71871794;0;2&lt;/code>
By playing with code we can see that last two parameters are count of received and sent messages. First two are more interesting. As we saw&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Ratchet&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">RatchetEncrypt&lt;/span>(self, plaintext, AD):
self&lt;span style="color:#f92672">.&lt;/span>CKs, mk &lt;span style="color:#f92672">=&lt;/span> KDF_CK(self&lt;span style="color:#f92672">.&lt;/span>CKs)
header &lt;span style="color:#f92672">=&lt;/span> HEADER(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>PN, self&lt;span style="color:#f92672">.&lt;/span>Ns)
self&lt;span style="color:#f92672">.&lt;/span>Ns &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> header, ENCRYPT(mk, plaintext, CONCAT(AD, header))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This means &lt;code>header_to_string&lt;/code> format looks like &lt;code>&amp;quot;self.DHs[0];self.DHs[1];to_m_count;from_m_count&amp;quot;&lt;/code>.
I found two places of &lt;code>self.DHs&lt;/code> generation:&lt;/p>
&lt;ol>
&lt;li>in &lt;code>_DHRatchet&lt;/code> which used in &lt;code>RatchetDecrypt&lt;/code> necessary for pulling messages (we&amp;rsquo;ll come back to that later.)&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Ratchet&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_DHRatchet&lt;/span>(self, header):
self&lt;span style="color:#f92672">.&lt;/span>PN &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>Ns
self&lt;span style="color:#f92672">.&lt;/span>Ns &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
self&lt;span style="color:#f92672">.&lt;/span>Nr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
self&lt;span style="color:#f92672">.&lt;/span>DHr &lt;span style="color:#f92672">=&lt;/span> header&lt;span style="color:#f92672">.&lt;/span>dh
self&lt;span style="color:#f92672">.&lt;/span>RK, self&lt;span style="color:#f92672">.&lt;/span>CKr &lt;span style="color:#f92672">=&lt;/span> KDF_RK(self&lt;span style="color:#f92672">.&lt;/span>RK, DH(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>DHr))
self&lt;span style="color:#f92672">.&lt;/span>DHs &lt;span style="color:#f92672">=&lt;/span> GENERATE_DH()
self&lt;span style="color:#f92672">.&lt;/span>RK, self&lt;span style="color:#f92672">.&lt;/span>CKs &lt;span style="color:#f92672">=&lt;/span> KDF_RK(self&lt;span style="color:#f92672">.&lt;/span>RK, DH(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>DHr))
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>in &lt;code>start_x3dh&lt;/code> which used in first &lt;code>client.send&lt;/code> call (actually &lt;code>self.DHs&lt;/code> modifying in &lt;code>receive_x3dh&lt;/code> but it also uses &lt;code>GENERATE_DH&lt;/code> algo)&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Client&lt;/span>:
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">start_x3dh&lt;/span>(self, m_to):
&lt;span style="color:#f92672">...&lt;/span>
DHs_A&lt;span style="color:#f92672">=&lt;/span>GENERATE_DH()
RK_A, CKs_A &lt;span style="color:#f92672">=&lt;/span> KDF_RK(SK, DH(DHs_A, PK_B))
self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict[m_to] &lt;span style="color:#f92672">=&lt;/span> Ratchet(DHs&lt;span style="color:#f92672">=&lt;/span>DHs_A, DHr&lt;span style="color:#f92672">=&lt;/span>PK_B, RK&lt;span style="color:#f92672">=&lt;/span>RK_A, CKs&lt;span style="color:#f92672">=&lt;/span>CKs_A)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send&lt;/span>(self, m_to, msg, send&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">True&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> m_to &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#f92672">in&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>RATCHET_dict&lt;span style="color:#f92672">.&lt;/span>keys():
self&lt;span style="color:#f92672">.&lt;/span>start_x3dh(m_to)
&lt;span style="color:#f92672">...&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Look at &lt;code>GENERATE_DH&lt;/code> function:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">GENERATE_DH&lt;/span>():
prv_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>prv_unmarshal(generate_bytes(&lt;span style="color:#ae81ff">64&lt;/span>))
pub_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>public_key(CURVE, prv_key)
&lt;span style="color:#66d9ef">return&lt;/span> (prv_key, pub_key)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Omg, it uses &lt;code>generate_bytes&lt;/code>, which uses &lt;code>random.randbytes&lt;/code>. This is why we got same header with fixed seed.&lt;/p>
&lt;p>Let&amp;rsquo;s hook &lt;code>generate_bytes&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">start_time &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1337&lt;/span> &lt;span style="color:#75715e">#int(time.time())&lt;/span>
random&lt;span style="color:#f92672">.&lt;/span>seed(start_time)
size&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">64&lt;/span>
MSG_NUM &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate_bytes&lt;/span>(n&lt;span style="color:#f92672">=&lt;/span>size):
&lt;span style="color:#66d9ef">global&lt;/span> MSG_NUM
rand &lt;span style="color:#f92672">=&lt;/span> random&lt;span style="color:#f92672">.&lt;/span>randbytes(n)
print(&lt;span style="color:#e6db74">&amp;#39;MSG_NUM CALLED&amp;#39;&lt;/span>, MSG_NUM)
print(&lt;span style="color:#e6db74">&amp;#39;GENERATED rand&amp;#39;&lt;/span>, debug_print_dh(rand))
MSG_NUM&lt;span style="color:#f92672">+=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> rand
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">debug_print_dh&lt;/span>(rand):
prv_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>prv_unmarshal(rand)
pub_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>public_key(CURVE, prv_key)
&lt;span style="color:#66d9ef">return&lt;/span> pub_key[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/HJ7GQqdnn.png" alt="">
yeah, that&amp;rsquo;s correct.
At this moment we know that all parameters generated with &lt;code>random&lt;/code> module and we know algo which used for that.&lt;/p>
&lt;h2 id="second-attempt-to-recover-random-seed-success">Second attempt to recover random seed (Success)&lt;/h2>
&lt;p>From task description we know &lt;code>He knows that it was 8th message between clients and they had started chat about 1 min before intercepted message&lt;/code>. Ok, &lt;code>Date: Sun, 16 Jul 2023 21:53:34 GMT&lt;/code> -&amp;gt; &lt;code>unix timestamp 1689544414&lt;/code>. Lets bruteforce time and compare our &lt;code>GENERATE_DH()&lt;/code> results with original header:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">from&lt;/span> pygost &lt;span style="color:#f92672">import&lt;/span> gost3410
&lt;span style="color:#f92672">import&lt;/span> random
search &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;10007557092155308918620703319005578742802155531542215927047486636897385017421026687658302411228112816312151375158019561914808361055666669789420151300043193&amp;#34;&lt;/span>
start_time &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1689544414&lt;/span> &lt;span style="color:#75715e"># int(time.time())&lt;/span>
random&lt;span style="color:#f92672">.&lt;/span>seed(start_time)
CURVE &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>CURVES[&lt;span style="color:#e6db74">&amp;#34;id-tc26-gost-3410-2012-512-paramSetA&amp;#34;&lt;/span>]
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">generate_bytes&lt;/span>(n&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">64&lt;/span>):
&lt;span style="color:#66d9ef">return&lt;/span> random&lt;span style="color:#f92672">.&lt;/span>randbytes(n)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">GENERATE_DH&lt;/span>():
prv_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>prv_unmarshal(generate_bytes(&lt;span style="color:#ae81ff">64&lt;/span>))
pub_key &lt;span style="color:#f92672">=&lt;/span> gost3410&lt;span style="color:#f92672">.&lt;/span>public_key(CURVE, prv_key)
&lt;span style="color:#66d9ef">return&lt;/span> (prv_key, pub_key)
&lt;span style="color:#66d9ef">for&lt;/span> j &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">200&lt;/span>):
t &lt;span style="color:#f92672">=&lt;/span> start_time &lt;span style="color:#f92672">-&lt;/span> j
print(j)
random&lt;span style="color:#f92672">.&lt;/span>seed(t)
arr &lt;span style="color:#f92672">=&lt;/span> [str((GENERATE_DH()[&lt;span style="color:#ae81ff">1&lt;/span>])[&lt;span style="color:#ae81ff">0&lt;/span>]) &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">20&lt;/span>)] &lt;span style="color:#75715e"># pub_key[0]&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span> search &lt;span style="color:#f92672">in&lt;/span> arr:
print(&lt;span style="color:#e6db74">&amp;#34;SEED RECOVERED&amp;#34;&lt;/span>, t)
print(&lt;span style="color:#e6db74">&amp;#34;MSG_NUM CALLED&amp;#34;&lt;/span>, arr&lt;span style="color:#f92672">.&lt;/span>index(search)&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#75715e"># because MSG_NUM beggining from 1&lt;/span>
&lt;span style="color:#66d9ef">break&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>and we see&lt;/p>
&lt;pre tabindex="0">&lt;code>64
65
66
SEED RECOVERED 1689544348
MSG_NUM CALLED 10
&lt;/code>&lt;/pre>&lt;p>then we have this &lt;code>GENERATE_DH&lt;/code>, in which we need&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">[
&lt;span style="color:#e6db74">&amp;#39;9264589598917214570356576028637286965316409427254818227493078254039255165721359928330096074586822045454591272668453788514652534124577717080803397323837753&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;5882838151079707917212895213006119673676890363161552333914448586032078639206645580866944258673556248686928883063120090222874182146824264129454879986035719&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;6356725936561061752235179817746125611162703105753208009200752643649999618267446822075106985582287873377398980657379412925058956059861218407756501430626927&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;2887626599271120182764806265394113921448284156247717458149074760790256212900772489341554363321357077449592555181818332405145513141515880148664404651010552&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;2216900006373410088238948423035178444110439136989098412941526318911086854342633422828594482332725423331627448229960406207026042091000046928246514259533395&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;2065978910820990851915215841599391978415392480535782437522299103928746742945880018832732484334365811051266269087678987390370004457623474476295627178062519&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;12580783417477889603032614422211297881357618632629370530972814208266292685499754494342954304811493970406677227245281245667848862501108323925026691208119146&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;11118815991327334922664302532246147692704095619978833554028959589828597949540394350413685937115099333628326943518745314022450906666032282699751140012678971&amp;#39;&lt;/span>,
&lt;span style="color:#e6db74">&amp;#39;649690232490058282951690312227812912664432393914555704120385988873130546340547752604856744054079240351159264632950984887792529728373140985426012556105651&amp;#39;&lt;/span>,
&lt;span style="color:#75715e"># original header:&lt;/span>
&lt;span style="color:#e6db74">&amp;#39;10007557092155308918620703319005578742802155531542215927047486636897385017421026687658302411228112816312151375158019561914808361055666669789420151300043193&amp;#39;&lt;/span>
]
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="repeat-traffic">Repeat traffic&lt;/h2>
&lt;p>Since we know all encryption keys, it will be easiest just repeat the same actions that the clients performed and decrypt the 8th message.&lt;/p>
&lt;p>Let&amp;rsquo;s patch encryption function by adding flag decryption:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">RatchetEncrypt&lt;/span>(self, plaintext, AD):
self&lt;span style="color:#f92672">.&lt;/span>CKs, mk &lt;span style="color:#f92672">=&lt;/span> KDF_CK(self&lt;span style="color:#f92672">.&lt;/span>CKs)
header &lt;span style="color:#f92672">=&lt;/span> HEADER(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>PN, self&lt;span style="color:#f92672">.&lt;/span>Ns)
self&lt;span style="color:#f92672">.&lt;/span>Ns &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
enc &lt;span style="color:#f92672">=&lt;/span> ENCRYPT(mk, plaintext, CONCAT(AD, header))
decrypted_text &lt;span style="color:#f92672">=&lt;/span> DECRYPT(mk, enc, CONCAT(AD, header))
&lt;span style="color:#75715e"># print(&amp;#39;MK = &amp;#39;, mk)&lt;/span>
print(&lt;span style="color:#e6db74">&amp;#39;decrypted: &amp;#39;&lt;/span>, decrypted_text)
ff &lt;span style="color:#f92672">=&lt;/span> unhexlify(&lt;span style="color:#e6db74">&amp;#39;b3f3ca9e16fc1c33c86bb08e9ecee860462cdd6716dd2c32a6701b978c76035ec2973e2c6eac490d54f7918a0167179037459cbda47e4abcd5028a405d8374ada62fd23e3fcb29ab1e36e44ef7cfa438&amp;#39;&lt;/span>)
print(&lt;span style="color:#e6db74">&amp;#39;FLAG&amp;#39;&lt;/span>, DECRYPT(mk, ff, CONCAT(AD, header))) &lt;span style="color:#75715e"># try to decrypt encrypted flag&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> header, enc
&lt;/code>&lt;/pre>&lt;/div>&lt;p>But if we run &lt;code>client.py&lt;/code> with correct seed, we can see this is not original header&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/HJGIzhO32.png" alt="">&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/rk5Uznuhh.png" alt="">
But why this header is not original? Why can&amp;rsquo;t we make some more calls &lt;code>GENERATE_DH&lt;/code> and then get correct header? The reason for this is that when sending multiple messages, the header is fixed after the first one.&lt;/p>
&lt;p>At this time we need to remember that we did not used &lt;code>pull messages&lt;/code> option yet.&lt;/p>
&lt;blockquote>
&lt;p>When i tried use this option During CTF in most cases it failed
&lt;img src="https://uvicorn.github.io/images/ByZ8QkKnh.png" alt="">&lt;/p>
&lt;p>I thought we need to send msg from B at the end. For this reason we can only connect, send msg from A, pull messages from A. But in sum it gives 4+2+1=7, not 9.&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/r1RltyYhh.png" alt="">&lt;/p>
&lt;p>I removed unpad function and it works well this time. But i can&amp;rsquo;t understand why author left bug in the source code, and hence i thought that we should not use this function.&lt;/p>
&lt;/blockquote>
&lt;p>Get back to the task.
As we remember we have &lt;code>to_m_count&lt;/code> and &lt;code>from_m_count&lt;/code> fields in header.&lt;/p>
&lt;p>By playing with client we can see that in original header &lt;code>to_m_count=2&lt;/code> (A-&amp;gt;B) and &lt;code>from_m_count=1 or 0&lt;/code> (B-&amp;gt;A). But as we&amp;rsquo;ll see later, this was another bug lol.&lt;/p>
&lt;p>Time to play with &lt;code>client.py&lt;/code> again (here we go again). I guessed that if we send &lt;code>2 1 3&lt;/code> (send msg + change client + pull msg) two times, then we can generate new header for client&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/H1-_bM5n2.png" alt="">&lt;/p>
&lt;p>Why it works? As we saw before, &lt;code>self.DHs&lt;/code> changes here, and it is used when constructing the header&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python"> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">RatchetDecrypt&lt;/span>(self, header, ciphertext, AD):
plaintext &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>_TrySkippedMessageKeys(header, ciphertext, AD)
&lt;span style="color:#66d9ef">if&lt;/span> plaintext &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> plaintext
&lt;span style="color:#66d9ef">if&lt;/span> header&lt;span style="color:#f92672">.&lt;/span>dh &lt;span style="color:#f92672">!=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>DHr:
self&lt;span style="color:#f92672">.&lt;/span>_SkipMessageKeys(header&lt;span style="color:#f92672">.&lt;/span>pn)
self&lt;span style="color:#f92672">.&lt;/span>_DHRatchet(header)
self&lt;span style="color:#f92672">.&lt;/span>_SkipMessageKeys(header&lt;span style="color:#f92672">.&lt;/span>n)
self&lt;span style="color:#f92672">.&lt;/span>CKr, mk &lt;span style="color:#f92672">=&lt;/span> KDF_CK(self&lt;span style="color:#f92672">.&lt;/span>CKr)
self&lt;span style="color:#f92672">.&lt;/span>Nr &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> DECRYPT(mk, ciphertext, CONCAT(AD, header))
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">_DHRatchet&lt;/span>(self, header):
self&lt;span style="color:#f92672">.&lt;/span>PN &lt;span style="color:#f92672">=&lt;/span> self&lt;span style="color:#f92672">.&lt;/span>Ns
self&lt;span style="color:#f92672">.&lt;/span>Ns &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
self&lt;span style="color:#f92672">.&lt;/span>Nr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
self&lt;span style="color:#f92672">.&lt;/span>DHr &lt;span style="color:#f92672">=&lt;/span> header&lt;span style="color:#f92672">.&lt;/span>dh
self&lt;span style="color:#f92672">.&lt;/span>RK, self&lt;span style="color:#f92672">.&lt;/span>CKr &lt;span style="color:#f92672">=&lt;/span> KDF_RK(self&lt;span style="color:#f92672">.&lt;/span>RK, DH(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>DHr))
print(&lt;span style="color:#e6db74">&amp;#39;HERE WE GO&amp;#39;&lt;/span>)
self&lt;span style="color:#f92672">.&lt;/span>DHs &lt;span style="color:#f92672">=&lt;/span> GENERATE_DH()
self&lt;span style="color:#f92672">.&lt;/span>RK, self&lt;span style="color:#f92672">.&lt;/span>CKs &lt;span style="color:#f92672">=&lt;/span> KDF_RK(self&lt;span style="color:#f92672">.&lt;/span>RK, DH(self&lt;span style="color:#f92672">.&lt;/span>DHs, self&lt;span style="color:#f92672">.&lt;/span>DHr))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>if we run we can see &lt;code>HERE WE GO&lt;/code> when we pull messages.
&lt;img src="https://uvicorn.github.io/images/rk7rZSc22.png" alt="">&lt;/p>
&lt;p>Final payload: &lt;code>213 213 213 213 2&lt;/code>.&lt;/p>
&lt;h2 id="epilogue">Epilogue&lt;/h2>
&lt;p>&lt;img src="https://uvicorn.github.io/images/S1WloFw2n.png" alt="">&lt;/p>
&lt;p>Task author told me that it was really Signal specification:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/rkjlOAw3h.png" alt="">&lt;/p>
&lt;blockquote>
&lt;p>-btw, did it really use the Signal specification?&lt;/p>
&lt;p>-Yeah you can look at it here. It was interesting to write it from scratch.))&lt;/p>
&lt;/blockquote>
&lt;p>&lt;a href="https://signal.org/docs/">https://signal.org/docs/&lt;/a>&lt;/p>
&lt;h2 id="the-first-attempt-to-recover-random-seed-fail">The first attempt to recover random seed (Fail)&lt;/h2>
&lt;p>On this step i lost more than 6 hours.
Since &lt;code>pull messages&lt;/code> options was broken, I thought to use only &lt;code>send msg&lt;/code>. And since only 8 messages are needed, it was easier to bruteforce all the combinations of sending them &lt;code>A-&amp;gt;B&lt;/code> or &lt;code>B-&amp;gt;A&lt;/code> (it need only 2^8 runs, but one run is ~5 seconds) and then we would get the right one. Of course it didn&amp;rsquo;t work&lt;/p>
&lt;p>You can see this shit &lt;a href="https://github.com/uvicorn/writeups/blob/master/ctfzone23%20-%20messager.zone/sploit/client2.py">here&lt;/a>&lt;/p>
- https://uvicorn.github.io/posts/ctfzone23-messenger.zone/ -</description></item><item><title>ImaginaryCTF 2022 reverse writeups</title><link>https://uvicorn.github.io/posts/ictf2022_rev/</link><pubDate>Wed, 20 Jul 2022 19:14:22 +0700</pubDate><guid>https://uvicorn.github.io/posts/ictf2022_rev/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/ictf2022_rev/ -&lt;h3 id="english-version---httpsuvicorngithubioictf2022_rev_en">English version - &lt;a href="https://uvicorn.github.io/ictf2022_rev_en/">https://uvicorn.github.io/ictf2022_rev_en/&lt;/a>&lt;/h3>
&lt;h2 id="вступление">Вступление&lt;/h2>
&lt;p>На прошедшем Imaginaryctf мы заняли 7 место, закрыв весь реверс.&lt;/p>
&lt;p>Небольшое описание задач:&lt;/p>
&lt;ol>
&lt;li>&lt;code>The House Always Wins&lt;/code> - glibc random prediction&lt;/li>
&lt;li>&lt;code>Jormungandr&lt;/code> - python virual machine&lt;/li>
&lt;li>&lt;code>One Liner Revenge&lt;/code> - python labyrinth&lt;/li>
&lt;li>&lt;code>xobeert&lt;/code> - another python virual machine&lt;/li>
&lt;li>&lt;code>wired&lt;/code> - avr rng&lt;/li>
&lt;/ol>
&lt;h2 id="the-house-always-wins">The House Always Wins&lt;/h2>
&lt;p>Дан &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/casino">бинарь&lt;/a> следующего содержания&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">get_rand&lt;/span>()
{
FILE &lt;span style="color:#f92672">*&lt;/span>stream; &lt;span style="color:#75715e">// [rsp+8h] [rbp-18h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> j; &lt;span style="color:#75715e">// [rsp+14h] [rbp-Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> i; &lt;span style="color:#75715e">// [rsp+18h] [rbp-8h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> seed; &lt;span style="color:#75715e">// [rsp+1Ch] [rbp-4h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
rand();
&lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!&lt;/span>init )
{
init &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
seed &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
stream &lt;span style="color:#f92672">=&lt;/span> fopen(&lt;span style="color:#e6db74">&amp;#34;/dev/urandom&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;r&amp;#34;&lt;/span>);
&lt;span style="color:#66d9ef">for&lt;/span> ( i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; i &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span>; &lt;span style="color:#f92672">++&lt;/span>i )
{
seed &lt;span style="color:#f92672">+=&lt;/span> fgetc(stream);
&lt;span style="color:#66d9ef">if&lt;/span> ( i &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span> )
seed &lt;span style="color:#f92672">&amp;lt;&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>;
}
fclose(stream);
srand(seed);
&lt;span style="color:#66d9ef">for&lt;/span> ( j &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; j &lt;span style="color:#f92672">&amp;lt;&lt;/span> rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>; &lt;span style="color:#f92672">++&lt;/span>j )
rand();
}
&lt;span style="color:#66d9ef">return&lt;/span> rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>; &lt;span style="color:#75715e">// 17 bit
&lt;/span>&lt;span style="color:#75715e">&lt;/span>}
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> argc, &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">**&lt;/span>argv, &lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">**&lt;/span>envp)
{
&lt;span style="color:#66d9ef">char&lt;/span> v3[&lt;span style="color:#ae81ff">59&lt;/span>]; &lt;span style="color:#75715e">// [rsp+0h] [rbp-70h] BYREF
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> aswer; &lt;span style="color:#75715e">// [rsp+3Bh] [rbp-35h] BYREF
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> stavka; &lt;span style="color:#75715e">// [rsp+3Ch] [rbp-34h] BYREF
&lt;/span>&lt;span style="color:#75715e">&lt;/span> FILE &lt;span style="color:#f92672">*&lt;/span>v6; &lt;span style="color:#75715e">// [rsp+40h] [rbp-30h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> rand2; &lt;span style="color:#75715e">// [rsp+4Ch] [rbp-24h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v8; &lt;span style="color:#75715e">// [rsp+50h] [rbp-20h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v9; &lt;span style="color:#75715e">// [rsp+54h] [rbp-1Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">float&lt;/span> v10; &lt;span style="color:#75715e">// [rsp+58h] [rbp-18h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">float&lt;/span> v11; &lt;span style="color:#75715e">// [rsp+5Ch] [rbp-14h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> rand; &lt;span style="color:#75715e">// [rsp+60h] [rbp-10h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> prize; &lt;span style="color:#75715e">// [rsp+64h] [rbp-Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> is_win; &lt;span style="color:#75715e">// [rsp+68h] [rbp-8h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> dollar; &lt;span style="color:#75715e">// [rsp+6Ch] [rbp-4h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
puts(&lt;span style="color:#e6db74">&amp;#34;You start with $100. Get 1 billion dollars, and we&amp;#39;ll give you the flag.&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;Run out of money, and we kick you out of the casino.&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;Are you feeling lucky?&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
dollar &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">100&lt;/span>;
&lt;span style="color:#66d9ef">while&lt;/span> ( &lt;span style="color:#ae81ff">1&lt;/span> )
{
rand &lt;span style="color:#f92672">=&lt;/span> get_rand();
printf(&lt;span style="color:#e6db74">&amp;#34;Current money: %u&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, dollar);
&lt;span style="color:#66d9ef">if&lt;/span> ( dollar &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1000000000&lt;/span> )
&lt;span style="color:#66d9ef">break&lt;/span>;
puts(&lt;span style="color:#e6db74">&amp;#34;How much are you betting? (minimum bet $5)&amp;#34;&lt;/span>);
printf(&lt;span style="color:#e6db74">&amp;#34;&amp;gt;&amp;gt;&amp;gt; &amp;#34;&lt;/span>);
__isoc99_scanf(&lt;span style="color:#e6db74">&amp;#34;%u%c&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;amp;&lt;/span>stavka, &lt;span style="color:#f92672">&amp;amp;&lt;/span>dead);
&lt;span style="color:#66d9ef">if&lt;/span> ( stavka &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#f92672">||&lt;/span> dollar &lt;span style="color:#f92672">&amp;lt;&lt;/span> stavka )
{
puts(&lt;span style="color:#e6db74">&amp;#34;You can&amp;#39;t bet that!&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;Get out of here, and come back with some real money!&amp;#34;&lt;/span>);
exit(&lt;span style="color:#ae81ff">1&lt;/span>);
}
dollar &lt;span style="color:#f92672">-=&lt;/span> stavka;
printf(&lt;span style="color:#e6db74">&amp;#34;The first number is %d.&lt;/span>&lt;span style="color:#ae81ff">\n\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, (&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>)rand);
v11 &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">float&lt;/span>)((&lt;span style="color:#66d9ef">float&lt;/span>)rand &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span>) &lt;span style="color:#f92672">/&lt;/span> &lt;span style="color:#ae81ff">65536.0&lt;/span>; &lt;span style="color:#f92672">/&lt;/span> (r&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)&lt;span style="color:#f92672">/&lt;/span>&lt;span style="color:#ae81ff">65536&lt;/span>
v10 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1.0&lt;/span> &lt;span style="color:#f92672">-&lt;/span> v11;
v9 &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span>)((&lt;span style="color:#66d9ef">double&lt;/span>)(&lt;span style="color:#66d9ef">int&lt;/span>)stavka &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">0.99&lt;/span> &lt;span style="color:#f92672">/&lt;/span> v11);
v8 &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span>)((&lt;span style="color:#66d9ef">double&lt;/span>)(&lt;span style="color:#66d9ef">int&lt;/span>)stavka &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">0.99&lt;/span> &lt;span style="color:#f92672">/&lt;/span> (&lt;span style="color:#66d9ef">float&lt;/span>)(&lt;span style="color:#ae81ff">1.0&lt;/span> &lt;span style="color:#f92672">-&lt;/span> v11));
printf(
&lt;span style="color:#e6db74">&amp;#34;Odds of higher: %.2f&lt;/span>&lt;span style="color:#ae81ff">\t&lt;/span>&lt;span style="color:#e6db74">Payout of higher: %u&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>,
(&lt;span style="color:#66d9ef">float&lt;/span>)(&lt;span style="color:#ae81ff">100.0&lt;/span> &lt;span style="color:#f92672">*&lt;/span> v10),
(&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>)(&lt;span style="color:#66d9ef">int&lt;/span>)((&lt;span style="color:#66d9ef">double&lt;/span>)(&lt;span style="color:#66d9ef">int&lt;/span>)stavka &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">0.99&lt;/span> &lt;span style="color:#f92672">/&lt;/span> v10));
printf(&lt;span style="color:#e6db74">&amp;#34;Odds of lower: %.2f&lt;/span>&lt;span style="color:#ae81ff">\t&lt;/span>&lt;span style="color:#e6db74">Payout of lower: %u&lt;/span>&lt;span style="color:#ae81ff">\n\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, (&lt;span style="color:#66d9ef">float&lt;/span>)(&lt;span style="color:#ae81ff">100.0&lt;/span> &lt;span style="color:#f92672">*&lt;/span> v11), v9);
puts(&lt;span style="color:#e6db74">&amp;#34;Do you think the next number will be:&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;1) Higher&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;2) Lower&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
puts(&lt;span style="color:#e6db74">&amp;#34;Remember, the house wins ties!&amp;#34;&lt;/span>);
printf(&lt;span style="color:#e6db74">&amp;#34;&amp;gt;&amp;gt;&amp;gt; &amp;#34;&lt;/span>);
__isoc99_scanf(&lt;span style="color:#e6db74">&amp;#34;%c%c&amp;#34;&lt;/span>, &lt;span style="color:#f92672">&amp;amp;&lt;/span>aswer, &lt;span style="color:#f92672">&amp;amp;&lt;/span>dead);
rand2 &lt;span style="color:#f92672">=&lt;/span> get_rand();
is_win &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
prize &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
printf(&lt;span style="color:#e6db74">&amp;#34;The second number is %d!&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, (&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>)rand2);
&lt;span style="color:#66d9ef">if&lt;/span> ( aswer &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;1&amp;#39;&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> rand &lt;span style="color:#f92672">&amp;lt;&lt;/span> rand2 )
{
is_win &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
prize &lt;span style="color:#f92672">=&lt;/span> v8;
}
&lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> ( aswer &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;2&amp;#39;&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> rand &lt;span style="color:#f92672">&amp;gt;&lt;/span> rand2 )
{
is_win &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
prize &lt;span style="color:#f92672">=&lt;/span> v9;
}
&lt;span style="color:#66d9ef">if&lt;/span> ( is_win )
{
printf(&lt;span style="color:#e6db74">&amp;#34;Congrats! You won %u dollars!&lt;/span>&lt;span style="color:#ae81ff">\n\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, prize);
dollar &lt;span style="color:#f92672">+=&lt;/span> prize;
}
&lt;span style="color:#66d9ef">else&lt;/span>
{
puts(&lt;span style="color:#e6db74">&amp;#34;You lost... Better luck next time!&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
}
}
v6 &lt;span style="color:#f92672">=&lt;/span> fopen(&lt;span style="color:#e6db74">&amp;#34;./flag.txt&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;r&amp;#34;&lt;/span>);
__isoc99_fscanf(v6, &lt;span style="color:#e6db74">&amp;#34;%s&amp;#34;&lt;/span>, v3);
printf(&lt;span style="color:#e6db74">&amp;#34;How&amp;#39;d you beat the house? %s&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, v3);
exit(&lt;span style="color:#ae81ff">0&lt;/span>);
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Нам дают результат &lt;code>get_rand&lt;/code> и просят по нему угадать будет ли больше или меньше результат вызова следующего &lt;code>get_rand&lt;/code>. Так как &lt;code>srand&lt;/code> вызывается один раз при первом запуске &lt;code>get_rand&lt;/code> , то функция приобретает вид&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">get_rand&lt;/span>()
{
rand();
&lt;span style="color:#66d9ef">return&lt;/span> rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>; &lt;span style="color:#75715e">// 17 bit
&lt;/span>&lt;span style="color:#75715e">&lt;/span>}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>В &lt;a href="https://www.mathstat.dal.ca/~selinger/random/">этой статье&lt;/a> хорошо описывается рандом в &lt;code>glibc&lt;/code> и как его предиктить:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720152934.png" alt="">&lt;/p>
&lt;p>Так как за один ход &lt;code>rand&lt;/code> вызывается 4 раза - &lt;code>[0,n1,0,n2]&lt;/code> (где &lt;code>n1&lt;/code> нам известен, 0 - нет, &lt;code>n2&lt;/code> нам нужно угадать), то выражение принимает вид &lt;code>o[i] = o[i-31-3] + o[i-31-31] + o[i-3-3] + o[i-3-31] = o[i-62] + o[i-9] + 2*o[i-34]&lt;/code>, следовательно &lt;code>i&amp;gt;=62&lt;/code>, то есть нам нужно &lt;code>62//4=16&lt;/code> раундов чтобы начать выигрывать. Нам понадобится примерно &lt;code>log(1000000000, 2)~=30&lt;/code> запросов чтобы достать флаг, то eсть можно не заморачиваться над оптимизацией всего этого.&lt;/p>
&lt;p>Для начала затестим алгоритм предсказания рандома на локалке:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">from&lt;/span> os &lt;span style="color:#f92672">import&lt;/span> urandom
&lt;span style="color:#f92672">from&lt;/span> ctypes &lt;span style="color:#f92672">import&lt;/span> CDLL
libc &lt;span style="color:#f92672">=&lt;/span> CDLL(&lt;span style="color:#e6db74">&amp;#34;libc.so.6&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">init&lt;/span>():
seed &lt;span style="color:#f92672">=&lt;/span> int&lt;span style="color:#f92672">.&lt;/span>from_bytes(urandom(&lt;span style="color:#ae81ff">8&lt;/span>), &lt;span style="color:#e6db74">&amp;#34;big&amp;#34;&lt;/span>)
libc&lt;span style="color:#f92672">.&lt;/span>srand(seed)
&lt;span style="color:#66d9ef">for&lt;/span> _ &lt;span style="color:#f92672">in&lt;/span> range(libc&lt;span style="color:#f92672">.&lt;/span>rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>):
libc&lt;span style="color:#f92672">.&lt;/span>rand()
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">get_random&lt;/span>():
libc&lt;span style="color:#f92672">.&lt;/span>rand()
&lt;span style="color:#66d9ef">return&lt;/span> libc&lt;span style="color:#f92672">.&lt;/span>rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>
init()
o &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">50&lt;/span>):
o&lt;span style="color:#f92672">.&lt;/span>append(&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)
libc&lt;span style="color:#f92672">.&lt;/span>rand()
o&lt;span style="color:#f92672">.&lt;/span>append(libc&lt;span style="color:#f92672">.&lt;/span>rand() &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>)
get_mod &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">lambda&lt;/span> x: ((x &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>) &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">2147483647&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">63&lt;/span>,&lt;span style="color:#ae81ff">100&lt;/span>,&lt;span style="color:#ae81ff">4&lt;/span>):
print(o[i] &lt;span style="color:#f92672">-&lt;/span> get_mod(o[i &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">62&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> o[i &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">6&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> o[i &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">34&lt;/span>] &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span>))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Работает! Разница между предсказанным и реальным значением меньше 4, что нам подходит, так как настолько точного результата и нам не надо.
Финальный код решения:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">from&lt;/span> pwn &lt;span style="color:#f92672">import&lt;/span> remote, context
context&lt;span style="color:#f92672">.&lt;/span>log_level &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;debug&amp;#34;&lt;/span>
r &lt;span style="color:#f92672">=&lt;/span> remote(&lt;span style="color:#e6db74">&amp;#34;the-house-always-wins.chal.imaginaryctf.org&amp;#34;&lt;/span>, &lt;span style="color:#ae81ff">1337&lt;/span>)
r&lt;span style="color:#f92672">.&lt;/span>recvlines(&lt;span style="color:#ae81ff">6&lt;/span>)
o &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">bet&lt;/span>():
current_money &lt;span style="color:#f92672">=&lt;/span> int(r&lt;span style="color:#f92672">.&lt;/span>recvline()&lt;span style="color:#f92672">.&lt;/span>split()[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>])
r&lt;span style="color:#f92672">.&lt;/span>recvline()
r&lt;span style="color:#f92672">.&lt;/span>recv(&lt;span style="color:#ae81ff">4&lt;/span>)
&lt;span style="color:#66d9ef">if&lt;/span> len(o) &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">31&lt;/span>:
r&lt;span style="color:#f92672">.&lt;/span>sendline(str(current_money)&lt;span style="color:#f92672">.&lt;/span>encode())
o&lt;span style="color:#f92672">.&lt;/span>append(int(r&lt;span style="color:#f92672">.&lt;/span>recvline()&lt;span style="color:#f92672">.&lt;/span>split()[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>][:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]))
predict &lt;span style="color:#f92672">=&lt;/span> (((o[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">17&lt;/span>] &lt;span style="color:#f92672">*&lt;/span> &lt;span style="color:#ae81ff">2&lt;/span> &lt;span style="color:#f92672">+&lt;/span> o[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">31&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> o[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>]) &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>) &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">2147483647&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">15&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span> predict &lt;span style="color:#f92672">&amp;gt;&lt;/span> o[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]:
status &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">b&lt;/span>&lt;span style="color:#e6db74">&amp;#34;1&amp;#34;&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
status &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">b&lt;/span>&lt;span style="color:#e6db74">&amp;#34;2&amp;#34;&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
r&lt;span style="color:#f92672">.&lt;/span>sendline(&lt;span style="color:#e6db74">b&lt;/span>&lt;span style="color:#e6db74">&amp;#34;5&amp;#34;&lt;/span>)
o&lt;span style="color:#f92672">.&lt;/span>append(int(r&lt;span style="color:#f92672">.&lt;/span>recvline()&lt;span style="color:#f92672">.&lt;/span>split()[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>][:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]))
status &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">b&lt;/span>&lt;span style="color:#e6db74">&amp;#34;1&amp;#34;&lt;/span>
r&lt;span style="color:#f92672">.&lt;/span>recvlines(&lt;span style="color:#ae81ff">9&lt;/span>)
r&lt;span style="color:#f92672">.&lt;/span>recv(&lt;span style="color:#ae81ff">4&lt;/span>)
r&lt;span style="color:#f92672">.&lt;/span>sendline(status)
o&lt;span style="color:#f92672">.&lt;/span>append(int(r&lt;span style="color:#f92672">.&lt;/span>recvline()&lt;span style="color:#f92672">.&lt;/span>split()[&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>][:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]))
r&lt;span style="color:#f92672">.&lt;/span>recvlines(&lt;span style="color:#ae81ff">2&lt;/span>)
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">200&lt;/span>):
bet()
&lt;span style="color:#75715e"># ictf{if_the_house_isn&amp;#39;t_using_cryptographically_secure_PRNG_the_house_deserves_to_lose}&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Здесь диллер дурак,&lt;br>
Ёр буллшит фак!&lt;br>
Порядок другоооооой!&lt;/p>
&lt;p>Ты где их береееееешь?&lt;br>
Ты дегенераааааааат!&lt;br>
Порядок у карт&lt;br>
В киосках был взяят,&lt;br>
Ты че, долбоеб?&lt;/p>
&lt;h2 id="jormungandr">Jormungandr&lt;/h2>
&lt;p>Нам дана следующая стековая виртуальная машина на питоне:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">find&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#66d9ef">lambda&lt;/span> v:(i&lt;span style="color:#f92672">:=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>,len([(i&lt;span style="color:#f92672">:=&lt;/span>i&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>)&lt;span style="color:#66d9ef">for&lt;/span>(c)&lt;span style="color:#f92672">in&lt;/span>(iter(&lt;span style="color:#66d9ef">lambda&lt;/span>:text[i]&lt;span style="color:#f92672">.&lt;/span>startswith(v), &lt;span style="color:#66d9ef">True&lt;/span>))]))[&lt;span style="color:#ae81ff">1&lt;/span>]
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p&lt;/span>(N):
Enter &lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
prime&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>&lt;span style="color:#75715e"># flag&lt;/span>
&lt;span style="color:#66d9ef">while&lt;/span> Enter&lt;span style="color:#f92672">&amp;lt;&lt;/span>N:
prime&lt;span style="color:#f92672">+=&lt;/span>(&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#f92672">+&lt;/span>prime&lt;span style="color:#f92672">%&lt;/span>&lt;span style="color:#ae81ff">2&lt;/span>)
s &lt;span style="color:#f92672">=&lt;/span>prime&lt;span style="color:#f92672">%&lt;/span>N
&lt;span style="color:#66d9ef">for&lt;/span>( hile)&lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">3&lt;/span>, prime,int( hex (&lt;span style="color:#ae81ff">2&lt;/span>),&lt;span style="color:#ae81ff">16&lt;/span>)):&lt;span style="color:#75715e"># salt&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span>( prime&lt;span style="color:#f92672">%&lt;/span>hile)&lt;span style="color:#f92672">==&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span> : &lt;span style="color:#66d9ef">break&lt;/span>
j__f &lt;span style="color:#f92672">=&lt;/span> prime
&lt;span style="color:#66d9ef">else&lt;/span>:
Enter&lt;span style="color:#f92672">+=&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span>(prime)
text&lt;span style="color:#f92672">=&lt;/span>open( __file__)&lt;span style="color:#f92672">.&lt;/span>read()&lt;span style="color:#f92672">.&lt;/span>split()
&lt;span style="color:#66d9ef">try&lt;/span>:
&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">False&lt;/span>:&lt;span style="color:#ae81ff">0&lt;/span>
&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
{&lt;span style="color:#f92672">**&lt;/span>{chr(i):&lt;span style="color:#66d9ef">lambda&lt;/span>:&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#66d9ef">for&lt;/span>(i)&lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">32&lt;/span>,&lt;span style="color:#ae81ff">127&lt;/span>)},&lt;span style="color:#f92672">**&lt;/span>{
&lt;span style="color:#e6db74">&amp;#39;l&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:text&lt;span style="color:#f92672">.&lt;/span>insert(find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>,input()),
&lt;span style="color:#e6db74">&amp;#39;s&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>)),
&lt;span style="color:#e6db74">&amp;#39;d&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:(text&lt;span style="color:#f92672">.&lt;/span>pop(),text&lt;span style="color:#f92672">.&lt;/span>pop()),
&lt;span style="color:#e6db74">&amp;#39;w&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:(text&lt;span style="color:#f92672">.&lt;/span>pop(find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>),text&lt;span style="color:#f92672">.&lt;/span>insert(find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>,text[&lt;span style="color:#ae81ff">1&lt;/span>])),
&lt;span style="color:#e6db74">&amp;#39;i&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:(b&lt;span style="color:#f92672">:=&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>],text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">1&lt;/span>),text&lt;span style="color:#f92672">.&lt;/span>insert(&lt;span style="color:#ae81ff">1&lt;/span>,(&lt;span style="color:#e6db74">&amp;#39;{:0&lt;/span>&lt;span style="color:#e6db74">%d&lt;/span>&lt;span style="color:#e6db74">x}&amp;#39;&lt;/span>&lt;span style="color:#f92672">%&lt;/span>(len(b)))&lt;span style="color:#f92672">.&lt;/span>format((int(b[:len(b)],&lt;span style="color:#ae81ff">16&lt;/span>)&lt;span style="color:#f92672">*&lt;/span>(&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#f92672">**&lt;/span>p(len(text)))&lt;span style="color:#f92672">+&lt;/span>p(len(text)))&lt;span style="color:#f92672">%&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>&lt;span style="color:#f92672">**&lt;/span>(len(b)))),text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))),&lt;span style="color:#75715e"># lit&lt;/span>
&lt;span style="color:#e6db74">&amp;#39;q&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:[text&lt;span style="color:#f92672">.&lt;/span>pop()&lt;span style="color:#66d9ef">for&lt;/span>( d)&lt;span style="color:#f92672">in&lt;/span> iter(int,&lt;span style="color:#ae81ff">1&lt;/span>)],
&lt;span style="color:#e6db74">&amp;#39;j&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:( chile &lt;span style="color:#f92672">:=&lt;/span>text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:],[text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;span style="color:#66d9ef">for&lt;/span>(i)&lt;span style="color:#f92672">in&lt;/span>(iter(&lt;span style="color:#66d9ef">lambda&lt;/span>:text[&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#f92672">.&lt;/span>startswith(chile),&lt;span style="color:#66d9ef">True&lt;/span>))]),&lt;span style="color:#e6db74">&amp;#39;p&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:print(text[&lt;span style="color:#ae81ff">1&lt;/span>],end&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39; j__f &amp;#39;&lt;/span>&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>),&lt;span style="color:#75715e"># kite ce10e59f40c8d954d9dad1ea81811a834d26580107149d16c3a769198fb158f0cb0e33dbd98f8dc8bb874105974b71719790b23c971736e8fe8ec88e8695 p&lt;/span>
&lt;span style="color:#e6db74">&amp;#39;not&amp;#39;&lt;/span> :&lt;span style="color:#66d9ef">lambda&lt;/span>: print(&lt;span style="color:#e6db74">&amp;#39; bad... &amp;#39;&lt;/span>),
&lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;span style="color:#66d9ef">if&lt;/span> text[find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#f92672">==&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>][&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#66d9ef">else&lt;/span>[text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;span style="color:#66d9ef">for&lt;/span>(i)&lt;span style="color:#f92672">in&lt;/span>&lt;span style="color:#e6db74">&amp;#39; q&amp;#39;&lt;/span>],
&lt;span style="color:#e6db74">&amp;#39;k&amp;#39;&lt;/span>:&lt;span style="color:#66d9ef">lambda&lt;/span>:text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;span style="color:#66d9ef">if&lt;/span> text[find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#f92672">==&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#66d9ef">else&lt;/span>[text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))&lt;span style="color:#66d9ef">for&lt;/span>(i)&lt;span style="color:#f92672">in&lt;/span>&lt;span style="color:#e6db74">&amp;#39; q&amp;#39;&lt;/span>],
}
}[text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">0&lt;/span>]]()
text&lt;span style="color:#f92672">.&lt;/span>append(text&lt;span style="color:#f92672">.&lt;/span>pop(&lt;span style="color:#ae81ff">0&lt;/span>))
&lt;span style="color:#66d9ef">except&lt;/span>:
&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Файл читает сам себя и, видимо, на этом основывается байткод для вм:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">text&lt;span style="color:#f92672">=&lt;/span>open(__file__)&lt;span style="color:#f92672">.&lt;/span>read()&lt;span style="color:#f92672">.&lt;/span>split()
&lt;span style="color:#f92672">...&lt;/span>
text&lt;span style="color:#f92672">.&lt;/span>insert(find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Эта проблема легко решается созданием нового файла и смены &lt;code>__file__&lt;/code> на &lt;code>original.py&lt;/code>&lt;/p>
&lt;p>&lt;code>text&lt;/code> явно является стеком нашей машины, а словарь &lt;code>{'l':lambda:..., 's': lambda: ...,}&lt;/code> похож на обработчики инструкций. Напишем для них дисассемблер:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">disp&lt;/span>(opc): &lt;span style="color:#75715e"># disp(text[0][0])&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;l&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;text[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">] = input()&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;s&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">&amp;#39;POPINS # &lt;/span>&lt;span style="color:#e6db74">{text[0]}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;d&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">&amp;#39;POP 2&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;w&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;POP text[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">] &amp;amp;&amp;amp; text[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">] = text[1] # &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;i&amp;#39;&lt;/span>:
b &lt;span style="color:#f92672">=&lt;/span> text[&lt;span style="color:#ae81ff">1&lt;/span>]
pp &lt;span style="color:#f92672">=&lt;/span> p(len(text)&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#75715e"># I spent 6 hours searching for an error in this opcode logger.&lt;/span>
res &lt;span style="color:#f92672">=&lt;/span> (int(b,&lt;span style="color:#ae81ff">16&lt;/span>)&lt;span style="color:#f92672">*&lt;/span>(&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#f92672">**&lt;/span>pp)&lt;span style="color:#f92672">+&lt;/span>pp) &lt;span style="color:#f92672">%&lt;/span> (&lt;span style="color:#ae81ff">16&lt;/span>&lt;span style="color:#f92672">**&lt;/span>(len(b))) &lt;span style="color:#75715e"># b*3**p + p mod 16**len(b)&lt;/span>
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;text[1] = (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>int(b,&lt;span style="color:#ae81ff">16&lt;/span>)&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> * &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>(&lt;span style="color:#ae81ff">3&lt;/span>&lt;span style="color:#f92672">**&lt;/span>pp)&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> + &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>pp&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) % (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>&lt;span style="color:#ae81ff">16&lt;/span>&lt;span style="color:#f92672">**&lt;/span>(len(b))&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) = &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>res&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> &amp;amp;&amp;amp; POPINS # pp = &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>pp&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;q&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;text = [] # QUIT&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;j&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;POPINS while (text[0] not start &amp;#39;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39; )&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;p&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;Print &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;if text[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">][1] (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) == text[1][0] (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>][&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) then POPINS else POPINS 2&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> opc &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;k&amp;#39;&lt;/span>:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;if text[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">] (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[find(text[&lt;span style="color:#ae81ff">0&lt;/span>][&lt;span style="color:#ae81ff">1&lt;/span>:])&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) == text[1] (&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>text[&lt;span style="color:#ae81ff">1&lt;/span>]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">) then POPINS else POPINS 2&lt;/span>
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;POPINS&amp;#34;&lt;/span>)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Небольшой комментарий к инструкциям:&lt;/p>
&lt;pre tabindex="0">&lt;code>l - считывает из ввода и кладет в стек
s - POPINS (POP &amp;amp; INSERT), то есть снимает нижний элемент стека и пушит его на верх( проще говоря, сдвигает стек на 1 элемент влево)
d - удаляет 2 верних элементов стека
w - удаляет элемент по индексу find(text[0][1:])+1, а затем кладет по этому же индексу text[1] # если find(text[0][1:])+1 == 0, то это будет find(...) вернет уже новый индекс
q - удаляет все элементы из стека, что вызывает exception, из-за чего работа машины прерывается
j - сдвигает стек влево пока text[i] не начинается с text[0][1:]
p - выводит text[1] в консоль
c, k - какие-то сравнения
i - пушит на верх стека b*3**p + p mod 16**len(b) (где b=text[1], pp = p(len(text)-1), функция p выдает n-ное простое число)
После этих и любых других опкодов вм сделает POPINS
&lt;/code>&lt;/pre>&lt;p>Итак, запускаем наш дисассемблер, вводя &lt;code>a&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220718230408.png" alt="">&lt;/p>
&lt;p>Как видим, в обработчик &lt;code>i&lt;/code> передается &lt;code>int(input(), 16)&lt;/code>, а затем результат функции идет дальше, пока не доходит до обработчика &lt;code>k&lt;/code> (сравнения), в котором сравнивает результаты с некой константой и в зависимости от этого выдает &lt;code>bad...&lt;/code> или &lt;code>not bad...&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220718231112.png" alt="">&lt;/p>
&lt;p>В итоге имеем уравнение вида &lt;code>((b * 3^p1 + p2) * 3^p3 + p4) * ... == 0xce10e... mod m&lt;/code>
Решаем его при помощи &lt;code>sage&lt;/code> и забираем флаг&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">m &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">16&lt;/span>&lt;span style="color:#f92672">**&lt;/span>&lt;span style="color:#ae81ff">124&lt;/span> &lt;span style="color:#75715e"># легко угадать, смотря на длину сравниваемой константы ~= log(0xce10..., 16)&lt;/span>
n &lt;span style="color:#f92672">=&lt;/span> Mod(&lt;span style="color:#ae81ff">0xce10e59f40c8d954d9dad1ea81811a834d26580107149d16c3a769198fb158f0cb0e33dbd98f8dc8bb874105974b71719790b23c971736e8fe8ec88e8695&lt;/span>,m)
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">277&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">1454077510067338869372316944847370699315973030897976908309312512336980481738317971337352174999857054574561953999845406588476984323763&lt;/span>
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">283&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">1060022504839090035772419052793733239801344339524625166157488821493658771187233801104929735574895792784855664465887301402999721572023227&lt;/span>
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">307&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">299381664701132778293030021884627147018656102332612973563127175701392996827190480510641050862491714816103809471587812971633152346558576658975844187&lt;/span>
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">313&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">218249233567125795375618885953893190176600298600474857727519711086315494687021860292257326078756460100939677104787515656320568060641202384393390412323&lt;/span>
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">331&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">84554224792451089968936207473892531191988484041341985013001115226199070159922911068116016183264280284215039063438883556666870418811396281309653281910088285947&lt;/span>
n &lt;span style="color:#f92672">-=&lt;/span> &lt;span style="color:#ae81ff">347&lt;/span>
n &lt;span style="color:#f92672">/=&lt;/span> &lt;span style="color:#ae81ff">3639782124011924976038695589926766574205325707740600894440840379831043263633626934257002144272462342660405490567954921015326460861727327341974159433117917530528729787&lt;/span>
print(long_to_bytes(n)) &lt;span style="color:#75715e"># ictf{welcome_to_the_flag_at_the_end_of_the_universe!_8762a9ab}&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="xobeert">xobeert&lt;/h2>
&lt;p>Нам дан &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/boxast.txt">дамп&lt;/a> &lt;code>ast&lt;/code> (абстрактное синтаксическое дерево) проги на питоне. Пытаемся распарсить его при помощи &lt;code>ast.unparse&lt;/code> (эту чудесную функцию ввели в 3.9), но получаем &lt;code>AttributeError: 'Assign' object has no attribute 'lineno'&lt;/code>, что фиксится при помощи &lt;code>ast.fix_missing_locations&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">from&lt;/span> ast &lt;span style="color:#f92672">import&lt;/span> &lt;span style="color:#f92672">*&lt;/span>
tree &lt;span style="color:#f92672">=&lt;/span> eval(open(&lt;span style="color:#e6db74">&amp;#39;boxast.txt&amp;#39;&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>read()[&lt;span style="color:#ae81ff">1&lt;/span>:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">3&lt;/span>])
tree &lt;span style="color:#f92672">=&lt;/span> ast&lt;span style="color:#f92672">.&lt;/span>fix_missing_locations(tree)
decompiled &lt;span style="color:#f92672">=&lt;/span> unparse(tree)
open(&lt;span style="color:#e6db74">&amp;#39;out.py&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;w&amp;#39;&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>write(decompiled)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Получаем еще один адовый обфусцированный &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/out.py">код&lt;/a> (привет one liner):&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720124506.png" alt="">&lt;/p>
&lt;p>Как видим, все завязано на декораторах. Легче всего понять что это на примере функцию &lt;code>main&lt;/code> из этой задачи, которую можно переписать следующим образом:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>():
&lt;span style="color:#66d9ef">pass&lt;/span>
main &lt;span style="color:#f92672">=&lt;/span> print(fffffffffffffffffffffffffffffffffff(main))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Так вот, начнем деобфускацию декораторов функции &lt;code>main&lt;/code>:&lt;/p>
&lt;ol>
&lt;li>первым декоратором на очереди будет функция, стоящая перед &lt;code>bytes.decode&lt;/code> на скрине выше:&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720125842.png" alt="">&lt;/p>
&lt;p>Как видим, эта функцию вызывает какой-то метод из &lt;code>random&lt;/code>, заведем функцию &lt;code>log&lt;/code>, чтобы посмотреть что находится в &lt;code>bytes.decode&lt;/code> перед вызовом &lt;code>random.__dict__.get&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">log&lt;/span>(string):
print(string)
&lt;span style="color:#66d9ef">return&lt;/span> string
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720130130.png" alt="">&lt;/p>
&lt;p>хорошо, это функция &lt;code>random.seed&lt;/code>.&lt;/p>
&lt;ol start="2">
&lt;li>поднимаемся по функции &lt;code>main&lt;/code> выше&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720130550.png" alt="">&lt;/p>
&lt;p>Функция берет длину нашего ввода, обзовем ее &lt;code>get_input_len&lt;/code> , а функцию с получением ввода &lt;code>get_input&lt;/code>&lt;/p>
&lt;ol start="3">
&lt;li>поднимаемся еще выше&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720130736.png" alt="">&lt;/p>
&lt;p>с помощью &lt;code>log&lt;/code> выясняем, что это &lt;code>random.randbytes&lt;/code>&lt;/p>
&lt;ol start="4">
&lt;li>идем дальше&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720132453.png" alt="">&lt;/p>
&lt;p>Эта функция ксорит наш ввод с массивом &lt;code>y&lt;/code>, который передается в нее, пока обзовем ее &lt;code>xor_with_input&lt;/code>&lt;/p>
&lt;ol start="5">
&lt;li>финал&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720135156.png" alt="">&lt;/p>
&lt;p>Последняя функция сравнивает переданное ей значение с неким константным массивом, который мы можем вытащить при помощи обычного принта (&lt;code>[123, 250, 94, 95, 121, 195, 249, 70, 71, 59, 137, 59, 5, 67, 65, 226, 17, 160, 205, 100, 251, 169, 50, 118, 184, 177, 1, 175, 133]&lt;/code>), а затем пишет &lt;code>wrong&lt;/code> или &lt;code>correct&lt;/code>. Обзовем функцию &lt;code>cmp_with_some_array&lt;/code>.&lt;/p>
&lt;p>Итак, у нас есть деобфусцированный &lt;code>main&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720140307.png" alt="">&lt;/p>
&lt;p>С помощью &lt;code>log&lt;/code> вытаскиваем изначальный сид для рандома - &lt;code>debdbeef_or_sth&lt;/code> , а дальше все довольно просто:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> random
cmp_arr &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">123&lt;/span>, &lt;span style="color:#ae81ff">250&lt;/span>, &lt;span style="color:#ae81ff">94&lt;/span>, &lt;span style="color:#ae81ff">95&lt;/span>, &lt;span style="color:#ae81ff">121&lt;/span>, &lt;span style="color:#ae81ff">195&lt;/span>, &lt;span style="color:#ae81ff">249&lt;/span>, &lt;span style="color:#ae81ff">70&lt;/span>, &lt;span style="color:#ae81ff">71&lt;/span>, &lt;span style="color:#ae81ff">59&lt;/span>, &lt;span style="color:#ae81ff">137&lt;/span>, &lt;span style="color:#ae81ff">59&lt;/span>, &lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#ae81ff">67&lt;/span>, &lt;span style="color:#ae81ff">65&lt;/span>, &lt;span style="color:#ae81ff">226&lt;/span>, &lt;span style="color:#ae81ff">17&lt;/span>, &lt;span style="color:#ae81ff">160&lt;/span>, &lt;span style="color:#ae81ff">205&lt;/span>, &lt;span style="color:#ae81ff">100&lt;/span>, &lt;span style="color:#ae81ff">251&lt;/span>, &lt;span style="color:#ae81ff">169&lt;/span>, &lt;span style="color:#ae81ff">50&lt;/span>, &lt;span style="color:#ae81ff">118&lt;/span>, &lt;span style="color:#ae81ff">184&lt;/span>, &lt;span style="color:#ae81ff">177&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">175&lt;/span>, &lt;span style="color:#ae81ff">133&lt;/span>]
random&lt;span style="color:#f92672">.&lt;/span>seed(&lt;span style="color:#e6db74">&amp;#39;debdbeef_or_sth&amp;#39;&lt;/span>)
seed2 &lt;span style="color:#f92672">=&lt;/span> random&lt;span style="color:#f92672">.&lt;/span>randbytes(len(cmp_arr)) &lt;span style="color:#75715e"># так как ввод должен сравниваться с массивом равной длины &lt;/span>
random&lt;span style="color:#f92672">.&lt;/span>seed(seed2)
print(xor(random&lt;span style="color:#f92672">.&lt;/span>randbytes(len(cmp_arr)), cmp_arr)) &lt;span style="color:#75715e"># ictf{wh0_n33d5_c4ll5_4nyw4y?}&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>P.S. этот таск был сломан и оргам удалось починить его только со второй попытки&lt;/p>
&lt;h2 id="one-liner-revenge">One Liner Revenge&lt;/h2>
&lt;p>Нам дают &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/revenge.py">файл&lt;/a> следующего содержания (дальше идут еще лямбды):&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220719195405.png" alt="">&lt;/p>
&lt;p>Я немного опешил. После jormungandr вообще не хотелось это решать, но все таки удалось себя убедить, что это сон и нужно лишь немного деобфусцировать код и все будет хорошо. Итак, первые строчки кода превращаются в&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#75715e"># globals().__setitem__(chr(0x67),globals())&lt;/span>
g &lt;span style="color:#f92672">=&lt;/span> globals()
&lt;span style="color:#75715e"># g.__setitem__(chr(0x74),lambda*a:bytes.fromhex(&amp;#39;{:x}&amp;#39;.format(a[0])).decode())&lt;/span>
t &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">lambda&lt;/span>&lt;span style="color:#f92672">*&lt;/span>a: bytes&lt;span style="color:#f92672">.&lt;/span>fromhex(&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">{:x}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>format(a[&lt;span style="color:#ae81ff">0&lt;/span>]))&lt;span style="color:#f92672">.&lt;/span>decode()
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Дальше по коду мы видим, что &lt;code>t&lt;/code> расшифровывает строчки. Заменяем ее вызовы на расшифрованные строчки, пытаясь привести код к человеческому виду:
&lt;img src="https://uvicorn.github.io/images/20220719200616.png" alt="">&lt;/p>
&lt;p>Это все таки лучше изначального ада, но все еще ужасно. На 7 строчке видим проверку на то, что файл не патчили (как ее обходить, думаю, и без меня понятно). Можно было бы и дальше деобфусцировать этот кринж, но мне в голову пришла идея получше. Что если протрейсить исполнение огромного массива лямбд и уже ориентироваться по ним что делать дальше? Итак, заводим функцию &lt;code>aboba&lt;/code> , которая будет нам с этим помогать, и пробуем ее вставить в лямбду:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">aboba&lt;/span>(a, &lt;span style="color:#f92672">*&lt;/span>equations):
print(a, equations)
&lt;span style="color:#66d9ef">return&lt;/span> equations
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#75715e"># *(lambda*a:(51*a[10]+56*a[0]+...), ...) -&amp;gt; *(lambda*a:aboba(a, 51*a[10]+56*a[0]+...)&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/20220719204009.png" alt="">&lt;/p>
&lt;p>Как видим, в лямбды передается наш ввод, а на выходе получаем результат исполнения 4 уравнений. Я сразу попытался сделать так, чтобы все уравнения выдали мне &lt;code>True&lt;/code>, но это не сработало. Тогда пробуем посмотреть в каком порядке лямбды исполняются:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">aboba&lt;/span>(a, num, &lt;span style="color:#f92672">*&lt;/span>equations):
print(a, num, equations)
&lt;span style="color:#66d9ef">return&lt;/span> equations
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#75715e"># *(lambda*a:(51*a[10]+56*a[0]+...), ...) -&amp;gt; *(lambda*a:aboba(a,1, 51*a[10]+56*a[0]+...)&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/20220719220725.png" alt="">&lt;/p>
&lt;p>То есть прога выходит после двух лямбд. Стоп, а что если подменить &lt;code>(False,False,False,False)&lt;/code>, допустим, на &lt;code>(2,2,2,2)&lt;/code> ? Прога выкидывает ошибку &lt;code>ValueError: invalid literal for int() with base 2: '2222'&lt;/code>, по которой мы находим ее виновника:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220719223509.png" alt="">&lt;/p>
&lt;p>Я предположил, что для перехода к следующей паре уравнений мне необходимо найти нужную пару результатов лямбд, то есть перебрать &lt;code>2^8=256&lt;/code>(в результате лямбды может быть 4 значения true или false) значений. Для этого пришлось немного извернуться, добавив в код новый инпут и убрав предыдующий:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">i2 &lt;span style="color:#f92672">=&lt;/span> list(map(int, input()&lt;span style="color:#f92672">.&lt;/span>split())) &lt;span style="color:#75715e"># вводим лишний 0, который преобразуется в (0,0,0,0) и (0,0,0,0), чтобы увидеть прошли ли мы на 2 следующих лямбды&lt;/span>
print(i2)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">to_bits&lt;/span>(i):
&lt;span style="color:#66d9ef">return&lt;/span> [int(j) &lt;span style="color:#66d9ef">for&lt;/span> j &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">{0:08b}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>format(int(i))]
bits &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> i2:bits&lt;span style="color:#f92672">.&lt;/span>extend(to_bits(i))
ctr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">aboba&lt;/span>(a, num, &lt;span style="color:#f92672">*&lt;/span>equations):
&lt;span style="color:#66d9ef">global&lt;/span> ctr
print(a, num, equations)
res &lt;span style="color:#f92672">=&lt;/span> bits[ctr&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">4&lt;/span>:ctr]
ctr&lt;span style="color:#f92672">+=&lt;/span>&lt;span style="color:#ae81ff">4&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> res
&lt;/code>&lt;/pre>&lt;/div>&lt;p>И запускаем все это при помощи костылей:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">for&lt;/span> i1 &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">256&lt;/span>):
os&lt;span style="color:#f92672">.&lt;/span>system(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;echo &amp;#39;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>i1&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39; | python3.9 ./ff2.py&amp;#34;&lt;/span>) &lt;span style="color:#75715e"># 0 это и есть одно лишнее значение&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720001408.png" alt="">&lt;/p>
&lt;p>18 (а точнее 0, 0, 0, 1 и 0, 0, 1, 0) и является нужным результатом первой пары лямбды, чтобы перейти к исполнению второй (лабиринт какой-то). Подобным образом дампим нужные значения оставшихся пар лямбд(я это сделал руками, нужно было всего 8 запросов) - &lt;code>[18, 52, 86, 120, 154, 188, 222, 240]&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220720111130.png" alt="">&lt;/p>
&lt;p>Ура, путь в лабиринте лямбд найден, осталось только сделать так, чтобы наш ввод позволил нам пройти его.
Итоговый скрипт для решения:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> z3
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">to_bits&lt;/span>(i):
&lt;span style="color:#66d9ef">return&lt;/span> [int(j) &lt;span style="color:#66d9ef">for&lt;/span> j &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#e6db74">{0:08b}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>format(int(i))]
ll &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">lambda&lt;/span> &lt;span style="color:#f92672">*&lt;/span>a: &lt;span style="color:#ae81ff">51&lt;/span>&lt;span style="color:#f92672">*&lt;/span>a[&lt;span style="color:#ae81ff">10&lt;/span>]&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">56&lt;/span>&lt;span style="color:#f92672">*&lt;/span>a[&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#f92672">+...&lt;/span> , &lt;span style="color:#66d9ef">lambda&lt;/span> &lt;span style="color:#f92672">*&lt;/span>a: &lt;span style="color:#f92672">...&lt;/span>)
sp &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">16&lt;/span>, &lt;span style="color:#ae81ff">1&lt;/span>, &lt;span style="color:#ae81ff">15&lt;/span>, &lt;span style="color:#ae81ff">2&lt;/span>, &lt;span style="color:#ae81ff">14&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span>, &lt;span style="color:#ae81ff">13&lt;/span>, &lt;span style="color:#ae81ff">4&lt;/span>, &lt;span style="color:#ae81ff">12&lt;/span>, &lt;span style="color:#ae81ff">5&lt;/span>, &lt;span style="color:#ae81ff">11&lt;/span>, &lt;span style="color:#ae81ff">6&lt;/span>, &lt;span style="color:#ae81ff">10&lt;/span>, &lt;span style="color:#ae81ff">7&lt;/span>, &lt;span style="color:#ae81ff">9&lt;/span>, &lt;span style="color:#ae81ff">8&lt;/span>]
lambd_results &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">18&lt;/span>, &lt;span style="color:#ae81ff">52&lt;/span>, &lt;span style="color:#ae81ff">86&lt;/span>, &lt;span style="color:#ae81ff">120&lt;/span>, &lt;span style="color:#ae81ff">154&lt;/span>, &lt;span style="color:#ae81ff">188&lt;/span>, &lt;span style="color:#ae81ff">222&lt;/span>, &lt;span style="color:#ae81ff">240&lt;/span>]
a &lt;span style="color:#f92672">=&lt;/span> [z3&lt;span style="color:#f92672">.&lt;/span>Int(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;flag[&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>i&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">]&amp;#34;&lt;/span>) &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">24&lt;/span>)]
cons &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">for&lt;/span> lambd_res &lt;span style="color:#f92672">in&lt;/span> lambd_results:
t &lt;span style="color:#f92672">=&lt;/span> to_bits(lambd_res)
cons&lt;span style="color:#f92672">.&lt;/span>append(t[:&lt;span style="color:#ae81ff">4&lt;/span>])
cons&lt;span style="color:#f92672">.&lt;/span>append(t[&lt;span style="color:#ae81ff">4&lt;/span>:])
s &lt;span style="color:#f92672">=&lt;/span> z3&lt;span style="color:#f92672">.&lt;/span>Solver()
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">16&lt;/span>):
l_result &lt;span style="color:#f92672">=&lt;/span> ll[sp[i]&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>](&lt;span style="color:#f92672">*&lt;/span>a)
&lt;span style="color:#66d9ef">for&lt;/span> j &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">4&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> cons[i][j] &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
s&lt;span style="color:#f92672">.&lt;/span>add(l_result[j])
&lt;span style="color:#66d9ef">else&lt;/span>:
s&lt;span style="color:#f92672">.&lt;/span>add(&lt;span style="color:#f92672">not&lt;/span> l_result[j])
&lt;span style="color:#66d9ef">for&lt;/span> k &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">24&lt;/span>):
s&lt;span style="color:#f92672">.&lt;/span>add(a[k] &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">126&lt;/span>)
s&lt;span style="color:#f92672">.&lt;/span>add(a[k] &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span>)
print(s&lt;span style="color:#f92672">.&lt;/span>check())
res &lt;span style="color:#f92672">=&lt;/span> s&lt;span style="color:#f92672">.&lt;/span>model()
flag &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> letter &lt;span style="color:#f92672">in&lt;/span> a:
flag &lt;span style="color:#f92672">+=&lt;/span> chr(res&lt;span style="color:#f92672">.&lt;/span>eval(letter)&lt;span style="color:#f92672">.&lt;/span>as_long())
print(flag)
&lt;span style="color:#75715e"># sat&lt;/span>
&lt;span style="color:#75715e"># ictf{0n3l1n3is5uperior!}&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="wired">wired&lt;/h2>
&lt;p>Нам дают &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/program.hex">прошивку&lt;/a> под ардуино и видосик с тем, как плата выдает нам флаг, зашифрованный при помощи &lt;code>hardware rng module&lt;/code>. Сам &lt;a href="https://github.com/uvicorn/writeups/blob/master/ictf2022/wired.mp4">видосик&lt;/a>.&lt;/p>
&lt;p>Находим хороший &lt;a href="https://blog.attify.com/flare-4-ctf-write-part-4/">райтап&lt;/a> с подробным гайдом по реверсу &lt;code>avr&lt;/code>, из которого мы забираем себе&lt;/p>
&lt;ol>
&lt;li>модуль процессора &lt;code>ATmega328&lt;/code> для иды&lt;/li>
&lt;li>плагин &lt;code>diaphora&lt;/code>, с помощью которого мы можем облегчить себе жизнь, найдя дифф между скомпиленным нами бинарем, содержащим встроенные функции, и нужным бинарем. Это нужно, чтобы восстановить имена функций, в нашем случае это восстановятся только 3 функции:&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721172219.png" alt="">&lt;/p>
&lt;p>Смотря на видосик и замеряя задержку, которая создается при помощи &lt;code>delay&lt;/code>, между порядком загорания светодиодов понимаем, что она примерно равна 200 миллисекундам, что соответствует следующему циклу:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721182142.png" alt="">&lt;/p>
&lt;p>Отсюда извлекаем порядок битов (Наскальные рисунки древних шизов в моем исполнении):&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721184919.png" alt="">&lt;/p>
&lt;p>Алгоритм шифрования:&lt;/p>
&lt;ol>
&lt;li>Генерируем &lt;code>random stream&lt;/code> (на самом деле он сразу ксорит его с флагом, но для простоты повествования опущу это)&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721182304.png" alt="">&lt;/p>
&lt;p>Видим цикл, в котором прога ждет ввода аналогового сигнал (вольтажа) и преобразует его в десятибитное число, которое разбивается на регистры &lt;code>r24&lt;/code> и &lt;code>r25&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721182049.png" alt="">&lt;/p>
&lt;p>Выясняем, что это &lt;code>seed&lt;/code> для нашего &lt;code>RNG&lt;/code>. Так как он занимает всего 10 бит, то нам понадобится &lt;code>2^10=1024&lt;/code> попыток чтобы угадать его, то есть его можно сбрутить.&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721182546.png" alt="">&lt;/p>
&lt;p>Алгоритм генерации &lt;code>rng stream&lt;/code> находится выше, втупую переписываем его на си, добавиви брут &lt;code>seed&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;string.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> orig[] &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#f92672">????&lt;/span>}; &lt;span style="color:#75715e">// вывод программы
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">check_rng&lt;/span>(&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r24, &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r25) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> work[&lt;span style="color:#ae81ff">21&lt;/span>];
memcpy(work, orig, &lt;span style="color:#ae81ff">21&lt;/span>);
&lt;span style="color:#66d9ef">for&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; i &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">20&lt;/span>; i &lt;span style="color:#f92672">++&lt;/span>) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">&amp;amp;&lt;/span>work[i];
&lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">^&lt;/span> r24;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r18 &lt;span style="color:#f92672">=&lt;/span> r24;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r19 &lt;span style="color:#f92672">=&lt;/span> r25;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> r25r24 &lt;span style="color:#f92672">=&lt;/span> (r25 &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>) &lt;span style="color:#f92672">|&lt;/span> r24;
r25r24 &lt;span style="color:#f92672">=&lt;/span> r25r24 &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
r25 &lt;span style="color:#f92672">=&lt;/span> (r25r24 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF00&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>;
r24 &lt;span style="color:#f92672">=&lt;/span> (r25r24 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF&lt;/span>);
&lt;span style="color:#66d9ef">if&lt;/span> (r18 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) {
r25 &lt;span style="color:#f92672">^=&lt;/span> &lt;span style="color:#ae81ff">0xAD&lt;/span>;
}
}
write(&lt;span style="color:#ae81ff">1&lt;/span>, work, &lt;span style="color:#ae81ff">20&lt;/span>);
}
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>() {
&lt;span style="color:#66d9ef">for&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> seed &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; seed &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">1024&lt;/span>; seed&lt;span style="color:#f92672">++&lt;/span>) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r24 &lt;span style="color:#f92672">=&lt;/span> (seed &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF00&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r25 &lt;span style="color:#f92672">=&lt;/span> (seed &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF&lt;/span>);
check_rng(r25, r24);
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;ol start="2">
&lt;li>ксорим флаг по адресу &lt;code>0x100&lt;/code> с &lt;code>rng stream&lt;/code>&lt;/li>
&lt;li>выводим его на светодиоды, некоторые из которых инвертированы&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://uvicorn.github.io/images/20220721183005.png" alt="">&lt;/p>
&lt;p>Если говорить совсем просто, то при попадании на ветку с &lt;code>sbrc&lt;/code> у нас инвертируется бит, при попадании на &lt;code>sbrs&lt;/code> - нет. Получаем маску, которая обозначает светодиоды, на которых биты инвертированы - &lt;code>0b10011010&lt;/code>&lt;/p>
&lt;p>Выводим формулу получения флага:
&lt;code>flag[i] ^ rng[i] ^ invert_mask = out[i] =&amp;gt; flag[i] = rng[i] ^ 0b10011010 ^ out[i]&lt;/code>&lt;/p>
&lt;p>По видосику определяем массив &lt;code>out&lt;/code> и сразу накладываем на него маску.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">a &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">0b01010110&lt;/span>, &lt;span style="color:#ae81ff">0b10101011&lt;/span>, &lt;span style="color:#ae81ff">0b01000111&lt;/span>, &lt;span style="color:#ae81ff">0b10101000&lt;/span>, &lt;span style="color:#ae81ff">0b11001011&lt;/span>, &lt;span style="color:#ae81ff">0b01111000&lt;/span>, &lt;span style="color:#ae81ff">0b00110101&lt;/span>, &lt;span style="color:#ae81ff">0b00010110&lt;/span>, &lt;span style="color:#ae81ff">0b10011010&lt;/span>, &lt;span style="color:#ae81ff">0b11000111&lt;/span>, &lt;span style="color:#ae81ff">0b01011001&lt;/span>, &lt;span style="color:#ae81ff">0b00100110&lt;/span>, &lt;span style="color:#ae81ff">0b10010011&lt;/span>, &lt;span style="color:#ae81ff">0b01001110&lt;/span>, &lt;span style="color:#ae81ff">0b10011100&lt;/span>, &lt;span style="color:#ae81ff">0b00001111&lt;/span>, &lt;span style="color:#ae81ff">0b11111101&lt;/span>, &lt;span style="color:#ae81ff">0b10000011&lt;/span>, &lt;span style="color:#ae81ff">0b01101101&lt;/span>, &lt;span style="color:#ae81ff">0b00101101&lt;/span>]
out &lt;span style="color:#f92672">=&lt;/span> list(map(&lt;span style="color:#66d9ef">lambda&lt;/span> o: o &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">0b10011010&lt;/span>, a)) &lt;span style="color:#75715e"># [204, 49, 221, 50, 81, 226, 175, 140, 0, 93, 195, 188, 9, 212, 6, 149, 103, 25, 247, 183]&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Итоговый код решения:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdlib.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;string.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> orig[] &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#ae81ff">204&lt;/span>, &lt;span style="color:#ae81ff">49&lt;/span>, &lt;span style="color:#ae81ff">221&lt;/span>, &lt;span style="color:#ae81ff">50&lt;/span>, &lt;span style="color:#ae81ff">81&lt;/span>, &lt;span style="color:#ae81ff">226&lt;/span>, &lt;span style="color:#ae81ff">175&lt;/span>, &lt;span style="color:#ae81ff">140&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>, &lt;span style="color:#ae81ff">93&lt;/span>, &lt;span style="color:#ae81ff">195&lt;/span>, &lt;span style="color:#ae81ff">188&lt;/span>, &lt;span style="color:#ae81ff">9&lt;/span>, &lt;span style="color:#ae81ff">212&lt;/span>, &lt;span style="color:#ae81ff">6&lt;/span>, &lt;span style="color:#ae81ff">149&lt;/span>, &lt;span style="color:#ae81ff">103&lt;/span>, &lt;span style="color:#ae81ff">25&lt;/span>, &lt;span style="color:#ae81ff">247&lt;/span>, &lt;span style="color:#ae81ff">183&lt;/span>, &lt;span style="color:#ae81ff">0&lt;/span>};
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">check_rng&lt;/span>(&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r24, &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r25) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> work[&lt;span style="color:#ae81ff">21&lt;/span>];
memcpy(work, orig, &lt;span style="color:#ae81ff">21&lt;/span>);
&lt;span style="color:#66d9ef">for&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; i &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">20&lt;/span>; i &lt;span style="color:#f92672">++&lt;/span>) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">&amp;amp;&lt;/span>work[i];
&lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">*&lt;/span>c &lt;span style="color:#f92672">^&lt;/span> r24;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r18 &lt;span style="color:#f92672">=&lt;/span> r24;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r19 &lt;span style="color:#f92672">=&lt;/span> r25;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> r25r24 &lt;span style="color:#f92672">=&lt;/span> (r25 &lt;span style="color:#f92672">&amp;lt;&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>) &lt;span style="color:#f92672">|&lt;/span> r24;
r25r24 &lt;span style="color:#f92672">=&lt;/span> r25r24 &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
r25 &lt;span style="color:#f92672">=&lt;/span> (r25r24 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF00&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>;
r24 &lt;span style="color:#f92672">=&lt;/span> (r25r24 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF&lt;/span>);
&lt;span style="color:#66d9ef">if&lt;/span> (r18 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) {
r25 &lt;span style="color:#f92672">^=&lt;/span> &lt;span style="color:#ae81ff">0xAD&lt;/span>;
}
}
write(&lt;span style="color:#ae81ff">1&lt;/span>, work, &lt;span style="color:#ae81ff">20&lt;/span>);
}
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>() {
&lt;span style="color:#66d9ef">for&lt;/span>(&lt;span style="color:#66d9ef">int&lt;/span> i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; i &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#ae81ff">1024&lt;/span>; i &lt;span style="color:#f92672">++&lt;/span>) {
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r24 &lt;span style="color:#f92672">=&lt;/span> (i &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF00&lt;/span>) &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>;
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> r25 &lt;span style="color:#f92672">=&lt;/span> (i &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">0xFF&lt;/span>);
check_rng(r25, r24);
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Запускаем:&lt;/p>
&lt;pre tabindex="0">&lt;code>./a.out | grep -oaiP 'ictf{.*?}'
ictf{weird_rng_912b}
&lt;/code>&lt;/pre>&lt;p>&lt;img src="https://uvicorn.github.io/images/maxresdefault1.jpg" alt="">&lt;/p>
- https://uvicorn.github.io/posts/ictf2022_rev/ -</description></item><item><title>Инъекция в процесс для обхода Nanomites</title><link>https://uvicorn.github.io/posts/nanomites/</link><pubDate>Sun, 29 May 2022 15:54:21 +0700</pubDate><guid>https://uvicorn.github.io/posts/nanomites/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/nanomites/ -&lt;!-- raw HTML omitted -->
&lt;h2 id="вступление">Вступление&lt;/h2>
&lt;p>После прочтения нескольких райтапов на реверс &lt;em>Nanomites&lt;/em> ( метод антиотладки, при котором родительский процесс запускает дочерний, с которым постоянно обменивается информацией, что и затрудняет дебаг) понял, что проще всего с этим бороться при помощи инъекции в процесс с переопределением функции &lt;code>ptrace&lt;/code>(мб не только ее). Проще всего это реализовать при помощи загрузки своей библиотеки через &lt;code>LD_PRELOAD&lt;/code>.&lt;/p>
&lt;p>Собсна, сами райтапы:&lt;/p>
&lt;ol>
&lt;li>&lt;a href="https://zenhack.it/rev/2020/10/28/10_-_break.html">Flareon 2020 task 10&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://lkmidas.github.io/posts/20210201-justctf2020-writeups/">Justctf 2020 debug_me_if_you_can&lt;/a>&lt;/li>
&lt;/ol>
&lt;h2 id="пример-инъекции-в-процесс-через-ld_preload">Пример инъекции в процесс через LD_PRELOAD&lt;/h2>
&lt;p>Код в &lt;code>main.c&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;#34;stdio.h&amp;#34;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">main&lt;/span>(){
puts(&lt;span style="color:#e6db74">&amp;#34;some message&amp;#34;&lt;/span>);
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Код &lt;code>lib.c&lt;/code>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#75715e">#define _GNU_SOURCE
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;lt;stdio.h&amp;gt;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">#include&lt;/span> &lt;span style="color:#75715e">&amp;#34;dlfcn.h&amp;#34;&lt;/span>&lt;span style="color:#75715e">
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">int&lt;/span> (&lt;span style="color:#f92672">*&lt;/span>default_puts)(&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span>&lt;span style="color:#f92672">*&lt;/span> message);
&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">puts&lt;/span>(&lt;span style="color:#66d9ef">const&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>message)
{
printf(&lt;span style="color:#e6db74">&amp;#34;OUR NEW MESSAGE: %s&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, message);
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
}
__attribute__((constructor)) &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> Constructor(&lt;span style="color:#66d9ef">void&lt;/span>) {
default_puts &lt;span style="color:#f92672">=&lt;/span> dlsym(RTLD_NEXT, &lt;span style="color:#e6db74">&amp;#34;puts&amp;#34;&lt;/span>);
default_puts(&lt;span style="color:#e6db74">&amp;#34;constructor called&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
}
__attribute__((destructor)) &lt;span style="color:#66d9ef">static&lt;/span> &lt;span style="color:#66d9ef">void&lt;/span> Destructor(&lt;span style="color:#66d9ef">void&lt;/span>) {
default_puts(&lt;span style="color:#e6db74">&amp;#34;destructor called&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Компиляция и запуск:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-shell" data-lang="shell">$ gcc lib.c -o mylib.so -fPIC -shared -ldl
$ gcc main.c -o f
$ LD_PRELOAD&lt;span style="color:#f92672">=&lt;/span>./mylib.so ./f
constructor
OUR NEW MESSAGE: some message
destructor
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;a href="https://uvicorn.github.io/nanomites/">FULL POST HERE&lt;/a>&lt;/p>
- https://uvicorn.github.io/posts/nanomites/ -</description></item><item><title>Forkbomb reverse ch2</title><link>https://uvicorn.github.io/posts/forkbomb_ch2-writeup/</link><pubDate>Sat, 12 Feb 2022 02:48:00 +0700</pubDate><guid>https://uvicorn.github.io/posts/forkbomb_ch2-writeup/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/forkbomb_ch2-writeup/ -&lt;p>Как писать райтапы, если решений не осталось&lt;/p>
&lt;h2 id="braindead">Braindead&lt;/h2>
&lt;p>Реверс брейнфака. Находим &lt;a href="https://excrupro.home.blog/2019/08/11/reversing-an-embedded-brainfuck-vm/">райтап&lt;/a> и следуя ему с помощью &lt;a href="https://github.com/paulkaefer/bftoc/blob/master/bftoc.py">этого скрипта&lt;/a> транслируем брейнфак в си, который позднее компилируем с -O3.
Закидываем &lt;a href="https://github.com/uvicorn/writeups/blob/master/forkbomb/braindead.o">бинарь&lt;/a> в иду и по вызовам &lt;code>putchar&lt;/code> находим нечто похожее на &lt;code>strcmp&lt;/code> по своей логике:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c"> v320 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">*&lt;/span>(_DWORD &lt;span style="color:#f92672">*&lt;/span>)&lt;span style="color:#f92672">&amp;amp;&lt;/span>v350[&lt;span style="color:#ae81ff">16&lt;/span>];
v322 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v319 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>;
&lt;span style="color:#66d9ef">do&lt;/span>
{
&lt;span style="color:#66d9ef">while&lt;/span> ( &lt;span style="color:#ae81ff">1&lt;/span> )
{
v323 &lt;span style="color:#f92672">=&lt;/span> v357;
&lt;span style="color:#66d9ef">if&lt;/span> ( v357 )
{
v357 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v321 &lt;span style="color:#f92672">+=&lt;/span> v323;
}
&lt;span style="color:#66d9ef">if&lt;/span> ( v321 )
v357 &lt;span style="color:#f92672">+=&lt;/span> v321;
v324 &lt;span style="color:#f92672">=&lt;/span> v320;
v325 &lt;span style="color:#f92672">=&lt;/span> v320 &lt;span style="color:#f92672">+&lt;/span> v323; &lt;span style="color:#75715e">// v325 = v323 // v323 - кол-во сиволов, которые совпали
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!&lt;/span>v323 )
v325 &lt;span style="color:#f92672">=&lt;/span> v324;
&lt;span style="color:#66d9ef">if&lt;/span> ( v325 &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span> ) &lt;span style="color:#75715e">// сравниваются только первые 32 символа -&amp;gt; длина флага = 32
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">break&lt;/span>;
&lt;span style="color:#f92672">++&lt;/span>v398;
v321 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v320 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!--&lt;/span>v319 )
&lt;span style="color:#66d9ef">goto&lt;/span> LABEL_989;
}
&lt;span style="color:#f92672">++&lt;/span>v322;
v321 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v320 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;span style="color:#f92672">--&lt;/span>v319;
}
&lt;span style="color:#66d9ef">while&lt;/span> ( v319 );
LABEL_989:
&lt;span style="color:#f92672">*&lt;/span>(_QWORD &lt;span style="color:#f92672">*&lt;/span>)&lt;span style="color:#f92672">&amp;amp;&lt;/span>v350[&lt;span style="color:#ae81ff">12&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0LL&lt;/span>;
v3 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v356 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
v358 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span>;
&lt;span style="color:#f92672">*&lt;/span>(_DWORD &lt;span style="color:#f92672">*&lt;/span>)&lt;span style="color:#f92672">&amp;amp;&lt;/span>v350[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> v322;
&lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!&lt;/span>v322 ) &lt;span style="color:#75715e">// if v322 == 0
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">goto&lt;/span> lose;
printf(&lt;span style="color:#e6db74">&amp;#34;Congratulations! The flag you have entered is correct&amp;#34;&lt;/span>);
lose:
printf(&lt;span style="color:#e6db74">&amp;#34;No, that&amp;#39;s wrong&amp;#34;&lt;/span>);
&lt;/code>&lt;/pre>&lt;/div>&lt;p>В дебаггере обнаруживаем, что в &lt;code>v323&lt;/code> (&lt;code>rdx&lt;/code>) хранится кол-во введенных символов, которые совпадают с символами флага.
Я, как существо ленивое, не захотел копаться в бинаре и решил написать нейросеть-брутфорсер:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> time
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;b *0x55555555888f&amp;#39;&lt;/span>) &lt;span style="color:#75715e"># адрес v325 = v320 + v323;&lt;/span>
dlt &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">32&lt;/span>&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#e6db74">&amp;#34;6&amp;#34;&lt;/span>
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;r &amp;lt;&amp;lt;&amp;lt;&amp;#34;&amp;#39;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> dlt &lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#34;&amp;#39;&lt;/span>)
m_val &lt;span style="color:#f92672">=&lt;/span> int(str(gdb&lt;span style="color:#f92672">.&lt;/span>parse_and_eval(&lt;span style="color:#e6db74">&amp;#34;$rdx&amp;#34;&lt;/span>)),&lt;span style="color:#ae81ff">16&lt;/span>)&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#75715e"># rdx - v323&lt;/span>
print(m_val, len(dlt))
time&lt;span style="color:#f92672">.&lt;/span>sleep(&lt;span style="color:#ae81ff">2&lt;/span>)
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>)
st &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(len(st),&lt;span style="color:#ae81ff">32&lt;/span>):
&lt;span style="color:#66d9ef">for&lt;/span> ch &lt;span style="color:#f92672">in&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#ae81ff">\&amp;#39;&lt;/span>&lt;span style="color:#e6db74">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345789{|}^_ !#$%&amp;amp;()*+,-./:;&amp;lt;=&amp;gt;?@&amp;#39;&lt;/span>:
print(st&lt;span style="color:#f92672">+&lt;/span>ch)
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;r &amp;lt;&amp;lt;&amp;lt;&amp;#34;&amp;#39;&lt;/span>&lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;6&amp;#34;&lt;/span>&lt;span style="color:#f92672">*&lt;/span>len(st) &lt;span style="color:#f92672">+&lt;/span> ch &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#e6db74">&amp;#34;6&amp;#34;&lt;/span>&lt;span style="color:#f92672">*&lt;/span>(&lt;span style="color:#ae81ff">31&lt;/span>&lt;span style="color:#f92672">-&lt;/span>len(st)) &lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&amp;#34;&amp;#39;&lt;/span>) &lt;span style="color:#75715e"># r &amp;lt;&amp;lt;&amp;lt; &amp;#34;6666666666666_66666666666666666&amp;#34;&lt;/span>
val &lt;span style="color:#f92672">=&lt;/span> int(str(gdb&lt;span style="color:#f92672">.&lt;/span>parse_and_eval(&lt;span style="color:#e6db74">&amp;#34;$rdx&amp;#34;&lt;/span>)),&lt;span style="color:#ae81ff">16&lt;/span>)
&lt;span style="color:#66d9ef">if&lt;/span> val &lt;span style="color:#f92672">&amp;gt;=&lt;/span> m_val:
st &lt;span style="color:#f92672">+=&lt;/span> ch
print(&lt;span style="color:#e6db74">&amp;#34;SUCCESS &amp;#34;&lt;/span>, st)
time&lt;span style="color:#f92672">.&lt;/span>sleep(&lt;span style="color:#ae81ff">3&lt;/span>)
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">break&lt;/span>
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Идея состоит в том, чтобы проверять каждый символ отдельно, заполняя 31 оставшийся шестерками (можно заполнять любыми символами), после чего переходить к следующему символу.
Стоит сказать, что нейросеть не идеальна, так как при переборе некоторых символов приходилось убавлять &lt;code>m_val&lt;/code> на 1, а иногда и вовсе оставлять символ неразгаданным. Тем не менее, минут через 15 получаем что-то похожее на флаг:&lt;code>spbctf{h4vE_%_B%%n_br41NWa5%3d?}&lt;/code>.
Находим возможные оставшиеся неизвестные символы (&lt;code>%&lt;/code>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">dct &lt;span style="color:#f92672">=&lt;/span> dict()
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;b *0x55555555888f&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">for&lt;/span> ch &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">32&lt;/span>,&lt;span style="color:#ae81ff">127&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> ch &lt;span style="color:#f92672">in&lt;/span> (&lt;span style="color:#ae81ff">34&lt;/span>,):&lt;span style="color:#66d9ef">continue&lt;/span> &lt;span style="color:#75715e"># двойная кавычка демотивировала гдб продолжать работу &lt;/span>
st &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;spbctf{h4vE_%_B&lt;/span>&lt;span style="color:#e6db74">%%&lt;/span>&lt;span style="color:#e6db74">n_br41NWa5&lt;/span>&lt;span style="color:#e6db74">%3d&lt;/span>&lt;span style="color:#e6db74">?}&amp;#34;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>replace(&lt;span style="color:#e6db74">&amp;#39;%&amp;#39;&lt;/span>,chr(ch))
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;r &amp;lt;&amp;lt;&amp;lt;&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>st&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&amp;#39;&lt;/span>)
val &lt;span style="color:#f92672">=&lt;/span> int(str(gdb&lt;span style="color:#f92672">.&lt;/span>parse_and_eval(&lt;span style="color:#e6db74">&amp;#34;$rdx&amp;#34;&lt;/span>)),&lt;span style="color:#ae81ff">16&lt;/span>)
dct[st] &lt;span style="color:#f92672">=&lt;/span> val
gdb&lt;span style="color:#f92672">.&lt;/span>execute(&lt;span style="color:#e6db74">&amp;#39;c&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">for&lt;/span> key, val &lt;span style="color:#f92672">in&lt;/span> dct&lt;span style="color:#f92672">.&lt;/span>items():
&lt;span style="color:#66d9ef">if&lt;/span> val &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">29&lt;/span>:
print(key, val)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>По завершению работы скрипта получаем&lt;/p>
&lt;pre tabindex="0">&lt;code>spbctf{h4vE_$_B$$n_br41NWa5$3d?} 23
spbctf{h4vE_1_B11n_br41NWa513d?} 30
spbctf{h4vE_3_B33n_br41NWa533d?} 30
spbctf{h4vE_\_B\\n_br41NWa5\3d?} 14
spbctf{h4vE_`_B``n_br41NWa5`3d?} 12
spbctf{h4vE_h_Bhhn_br41NWa5h3d?} 30
&lt;/code>&lt;/pre>&lt;p>Соответственно, возможные оставшиеся символы - &lt;code>1&lt;/code>, &lt;code>3&lt;/code>, &lt;code>h&lt;/code>.
Ручками подгоняем флаг до &lt;code>spbctf{h4vE_1_B33n_br41NWa5h3d?}&lt;/code>.&lt;/p>
&lt;h2 id="catgirl-industrials-shell">CatGirl Industrials Shell&lt;/h2>
&lt;p>Реверс виртуальной машины на питоне.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">avogado6&lt;/span>(&lt;span style="color:#f92672">*&lt;/span>args):
exit(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">beca&lt;/span>(st):
padding &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;=&amp;#34;&lt;/span> &lt;span style="color:#f92672">*&lt;/span> ((&lt;span style="color:#ae81ff">4&lt;/span> &lt;span style="color:#f92672">-&lt;/span> len(st)) &lt;span style="color:#f92672">%&lt;/span> &lt;span style="color:#ae81ff">4&lt;/span>)
mpl &lt;span style="color:#f92672">=&lt;/span> list(b64decode(st &lt;span style="color:#f92672">+&lt;/span> padding))
&lt;span style="color:#66d9ef">return&lt;/span> mpl
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">do_magic&lt;/span>(st): &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>join(chr(ord(i) &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">0x13&lt;/span> &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">0x37&lt;/span>) &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> st)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">pet_the_cat&lt;/span>(st): &lt;span style="color:#66d9ef">return&lt;/span> sum(ord(i) &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> st)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">love&lt;/span>(a0, a1): &lt;span style="color:#66d9ef">return&lt;/span> a0&lt;span style="color:#f92672">+&lt;/span>a1
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">peace&lt;/span>(a0, a1): &lt;span style="color:#66d9ef">return&lt;/span> a0 &lt;span style="color:#f92672">-&lt;/span> a1
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">hopes_and_dreams&lt;/span>(st): &lt;span style="color:#66d9ef">return&lt;/span> st
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_outer_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_naruto_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_conti_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_petergeize_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_non_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_romane_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_rerere_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_outer_pointer_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_ghost_out_of_the_shell_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">_ghost_in_the_shell_&lt;/span>:&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">dmagic&lt;/span>(xval, st):
ans &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;&amp;#34;&lt;/span>
st &lt;span style="color:#f92672">=&lt;/span> bytes(st&lt;span style="color:#f92672">.&lt;/span>encode())
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(len(st)):
ans &lt;span style="color:#f92672">+=&lt;/span> chr(st[i] &lt;span style="color:#f92672">^&lt;/span> xval)
xval &lt;span style="color:#f92672">^=&lt;/span> (ord(ans[i]) &lt;span style="color:#f92672">|&lt;/span> st[i])
&lt;span style="color:#66d9ef">return&lt;/span> ans
memory &lt;span style="color:#f92672">=&lt;/span> [ &lt;span style="color:#75715e"># bytecode&lt;/span>
print,
do_magic,
&lt;span style="color:#ae81ff">0&lt;/span>,
&lt;span style="color:#f92672">...&lt;/span>
]
data &lt;span style="color:#f92672">=&lt;/span> [ &lt;span style="color:#75715e"># stack &lt;/span>
[do_magic(&lt;span style="color:#e6db74">&amp;#34;Welcome to our CatGirl Industrials shell! There is an offline auth&amp;#34;&lt;/span>)],
&lt;span style="color:#f92672">...&lt;/span>
]
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">execute&lt;/span>():
pointer &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;span style="color:#66d9ef">if&lt;/span> memory[pointer] &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
print(&lt;span style="color:#e6db74">&amp;#34;STOP VM&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">break&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _petergeize_:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
jt &lt;span style="color:#f92672">=&lt;/span> memory[pointer]
pointer &lt;span style="color:#f92672">+=&lt;/span> jt&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _romane_:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
pointer &lt;span style="color:#f92672">=&lt;/span> memory[pointer] &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _conti_:
p0, p1 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop(), data&lt;span style="color:#f92672">.&lt;/span>pop()
data&lt;span style="color:#f92672">.&lt;/span>append([&lt;span style="color:#f92672">*&lt;/span>p0, &lt;span style="color:#f92672">*&lt;/span>p1])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _non_:
p0, p1 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop(), data&lt;span style="color:#f92672">.&lt;/span>pop()
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
jp &lt;span style="color:#f92672">=&lt;/span> memory[pointer]
&lt;span style="color:#66d9ef">if&lt;/span> p0 &lt;span style="color:#f92672">==&lt;/span> p1:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
pointer &lt;span style="color:#f92672">+=&lt;/span> jp&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _rerere_:
f0, o0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()[&lt;span style="color:#ae81ff">0&lt;/span>], data&lt;span style="color:#f92672">.&lt;/span>pop()[&lt;span style="color:#ae81ff">0&lt;/span>]
memory[pointer&lt;span style="color:#f92672">+&lt;/span>o0] &lt;span style="color:#f92672">=&lt;/span> f0
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _ghost_in_the_shell_:
f0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
data&lt;span style="color:#f92672">.&lt;/span>append([f0])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _ghost_out_of_the_shell_:
f0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
f0 &lt;span style="color:#f92672">=&lt;/span> f0[&lt;span style="color:#ae81ff">0&lt;/span>]
data&lt;span style="color:#f92672">.&lt;/span>append(f0)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _naruto_:
p0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
data&lt;span style="color:#f92672">.&lt;/span>append(p0)
data&lt;span style="color:#f92672">.&lt;/span>append(p0)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _outer_:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
p0 &lt;span style="color:#f92672">=&lt;/span> memory[pointer]
data&lt;span style="color:#f92672">.&lt;/span>append([p0])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _outer_pointer_:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
data&lt;span style="color:#f92672">.&lt;/span>append([pointer])
&lt;span style="color:#66d9ef">else&lt;/span>:
fcall &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">while&lt;/span> memory[pointer] &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
fcall&lt;span style="color:#f92672">.&lt;/span>append(memory[pointer])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
param &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
&lt;span style="color:#66d9ef">for&lt;/span> fun &lt;span style="color:#f92672">in&lt;/span> fcall[::&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]:
param &lt;span style="color:#f92672">=&lt;/span> [fun(&lt;span style="color:#f92672">*&lt;/span>param)]
&lt;span style="color:#66d9ef">if&lt;/span> param[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
data&lt;span style="color:#f92672">.&lt;/span>append(param)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
execute()
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Переименуем функции:&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-clike" data-lang="clike">avogado6 -&amp;gt; ext
do_magic -&amp;gt; xor_36
pet_the_cat -&amp;gt; sum_chars
love -&amp;gt; add
peace -&amp;gt; sub
hopes_and_dreams -&amp;gt; nop
_outer_ -&amp;gt; PUSH
_naruto_ -&amp;gt; COPY
_conti_ -&amp;gt; DOUBLE_PACK
_petergeize_ -&amp;gt; JMP_PLUS
_non_ -&amp;gt; JNE
_romane_ -&amp;gt; JMP
_rerere_ -&amp;gt; _rerere_ # инструкция не использовалась в байткоде, поэтому я забил на ее переименование
_outer_pointer_ -&amp;gt; PUSH_PTR
_ghost_out_of_the_shell_ -&amp;gt; UNPACK
_ghost_in_the_shell_ -&amp;gt; PACK
&lt;/code>&lt;/pre>&lt;p>И встроим в обработчик инструкций дисассемблер:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">ext&lt;/span>(&lt;span style="color:#f92672">*&lt;/span>args):
p(&lt;span style="color:#e6db74">&amp;#39;EXIT&amp;#39;&lt;/span>)
exit(&lt;span style="color:#ae81ff">1&lt;/span>)
DEBUG &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">p&lt;/span>(&lt;span style="color:#f92672">*&lt;/span>args): &lt;span style="color:#75715e"># debug print&lt;/span>
&lt;span style="color:#66d9ef">global&lt;/span> pointer
&lt;span style="color:#66d9ef">if&lt;/span> DEBUG:
print(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>pointer&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;gt;&amp;#34;&lt;/span>, &lt;span style="color:#f92672">*&lt;/span>args)
pointer &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;span style="color:#66d9ef">if&lt;/span> memory[pointer] &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>: &lt;span style="color:#75715e"># EXIT&lt;/span>
p(&lt;span style="color:#e6db74">&amp;#39;EXIT&amp;#39;&lt;/span>)
print(&lt;span style="color:#e6db74">&amp;#34;STOP VM&amp;#34;&lt;/span>)
&lt;span style="color:#66d9ef">break&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> JMP_PLUS: &lt;span style="color:#75715e"># JMP pointer+arg&lt;/span>
addr &lt;span style="color:#f92672">=&lt;/span> memory[pointer&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;JMP_PLUS &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>addr&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
pointer &lt;span style="color:#f92672">+=&lt;/span> addr
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> JMP: &lt;span style="color:#75715e"># JMP arg&lt;/span>
pointer &lt;span style="color:#f92672">=&lt;/span> memory[pointer&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;JMP &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>pointer&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> DOUBLE_PACK: &lt;span style="color:#75715e"># PUSH [POP, POP]&lt;/span>
p(&lt;span style="color:#e6db74">&amp;#39;POP; POP; PACK&amp;#39;&lt;/span>)
p0, p1 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop(), data&lt;span style="color:#f92672">.&lt;/span>pop()
data&lt;span style="color:#f92672">.&lt;/span>append([&lt;span style="color:#f92672">*&lt;/span>p0, &lt;span style="color:#f92672">*&lt;/span>p1])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> JNE: &lt;span style="color:#75715e"># JNE arg&lt;/span>
p0, p1 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop(), data&lt;span style="color:#f92672">.&lt;/span>pop()
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
jp &lt;span style="color:#f92672">=&lt;/span> memory[pointer]
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;CMP &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>p0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> == &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>p1&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">; JNE &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>jp&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">if&lt;/span> p0 &lt;span style="color:#f92672">==&lt;/span> p1:
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
pointer &lt;span style="color:#f92672">+=&lt;/span> jp&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> _rerere_: &lt;span style="color:#75715e"># я хз что это вообще&lt;/span>
f0, o0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()[&lt;span style="color:#ae81ff">0&lt;/span>], data&lt;span style="color:#f92672">.&lt;/span>pop()[&lt;span style="color:#ae81ff">0&lt;/span>]
memory[pointer&lt;span style="color:#f92672">+&lt;/span>o0] &lt;span style="color:#f92672">=&lt;/span> f0
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> PACK: &lt;span style="color:#75715e"># PUSH [POP] # [3] -&amp;gt; [[3]]&lt;/span>
f0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;PACK # &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>f0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74"> =&amp;gt; [&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>f0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">]&amp;#39;&lt;/span>)
data&lt;span style="color:#f92672">.&lt;/span>append([f0])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> UNPACK: &lt;span style="color:#75715e"># [[3]] -&amp;gt; [3]&lt;/span>
f0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
f0 &lt;span style="color:#f92672">=&lt;/span> f0[&lt;span style="color:#ae81ff">0&lt;/span>]
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;UNPACK # [&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>f0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">] =&amp;gt; &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>f0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
data&lt;span style="color:#f92672">.&lt;/span>append(f0)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> COPY: &lt;span style="color:#75715e"># pop ; push; push # копирует элемент на стеке&lt;/span>
p0 &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;POP &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>p0&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">; PUSH ; PUSH&amp;#34;&lt;/span>)
data&lt;span style="color:#f92672">.&lt;/span>append(p0)
data&lt;span style="color:#f92672">.&lt;/span>append(p0)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> PUSH: &lt;span style="color:#75715e"># PUSH arg&lt;/span>
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
p0 &lt;span style="color:#f92672">=&lt;/span> memory[pointer]
data&lt;span style="color:#f92672">.&lt;/span>append([p0])
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;PUSH &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>[p0]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">elif&lt;/span> memory[pointer] &lt;span style="color:#f92672">is&lt;/span> PUSH_PTR: &lt;span style="color:#75715e"># PUSH pointer&lt;/span>
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
p(&lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#39;PUSH PTR &lt;/span>&lt;span style="color:#e6db74">{&lt;/span>[pointer]&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)
data&lt;span style="color:#f92672">.&lt;/span>append([pointer])
&lt;span style="color:#66d9ef">else&lt;/span>:
fcall &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">while&lt;/span> memory[pointer] &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
fcall&lt;span style="color:#f92672">.&lt;/span>append(memory[pointer])
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
param &lt;span style="color:#f92672">=&lt;/span> data&lt;span style="color:#f92672">.&lt;/span>pop()
st &lt;span style="color:#f92672">=&lt;/span> str(param)[&lt;span style="color:#ae81ff">1&lt;/span>:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]
&lt;span style="color:#66d9ef">for&lt;/span> fun &lt;span style="color:#f92672">in&lt;/span> fcall[::&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]:
st &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">f&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>fun&lt;span style="color:#f92672">.&lt;/span>__name__&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">(&lt;/span>&lt;span style="color:#e6db74">{&lt;/span>st&lt;span style="color:#e6db74">}&lt;/span>&lt;span style="color:#e6db74">)&amp;#34;&lt;/span>
param &lt;span style="color:#f92672">=&lt;/span> [fun(&lt;span style="color:#f92672">*&lt;/span>param)]
p(&lt;span style="color:#e6db74">&amp;#34;PUSH &amp;#34;&lt;/span>&lt;span style="color:#f92672">+&lt;/span>st)
&lt;span style="color:#66d9ef">if&lt;/span> param[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#f92672">not&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
data&lt;span style="color:#f92672">.&lt;/span>append(param)
pointer &lt;span style="color:#f92672">+=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Перед тем, как приступим к реверсу байткода, скажу, что вы можете скачать код с дисассемблером &lt;a href="https://github.com/uvicorn/writeups/blob/master/forkbomb/rev_catgirlindustrials_shell.py">тут&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>Находим первые пять символов флага в &lt;code>CMP&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/S9NG5uw.png" alt="">&lt;/p>
&lt;p>Ради следующих шести придется развернуть строку &lt;code>moc.eb&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/d1S0ScO.png" alt="">&lt;/p>
&lt;p>Ксор &lt;code>xor_36('\x0bSEPGL\x1bR\x19') == '/watch?v='&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/Y2XXj8Q.png" alt="">&lt;/p>
&lt;p>Опять сравнение с &lt;code>CMP&lt;/code>&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/dnO2agT.png" alt="">&lt;/p>
&lt;p>На последнем шаге нужно будет дисассемблировать байткод чуть дальше текущего указателя и получить нужный массив (последняя часть флага - &lt;code>b64encode(bytes([27, 97, 79, 25, 132]))&lt;/code>)&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/YzY02TJ.png" alt="">&lt;/p>
&lt;p>Соберем флаг воедино: &lt;code>youtube.com/watch?v=H3w1G2FPGYQ&lt;/code>&lt;/p>
&lt;p>ЗЫ: Автор таска сказал, что по данному адресу должны были находиться бурятские песенки, но правообладатель их заблочил&lt;/p>
&lt;h2 id="movfuscator">Movfuscator&lt;/h2>
&lt;p>Решение этого таска я объяснить не могу, потому что решил его при помощи своих экстрасенсорных навыков.&lt;/p>
&lt;p>Итак, нам дают бинарник, состоящий из инструкций вида &lt;code>mov rcx, 0x1234&lt;/code>.
Да, можно было заосинтить &lt;a href="https://github.com/kirschju/demovfuscator">деобфускатор&lt;/a>, но это путь слабых.
Я же после пары запусков подопытного угадал алгоритм шифрования&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">st &lt;span style="color:#f92672">=&lt;/span> input()
res &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(len(st)):
res &lt;span style="color:#f92672">+=&lt;/span> chr(ord(st[i]) &lt;span style="color:#f92672">-&lt;/span> i)
print(res)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://uvicorn.github.io/images/vxicEUz.png" alt="">&lt;/p>
&lt;blockquote>
&lt;p>Что здесь происходит догадаться нетрудно&lt;/p>
&lt;/blockquote>
&lt;p>Затем закинул бинарь в гдб и начал прожимать &lt;code>nexti&lt;/code>, просматривая память в поисках шифротекста, с которым сравнивается наш ввод.
Где-то на адресе &lt;code>0x4006f0&lt;/code> обнаруживаю заветную строку:
&lt;code>t2f\iDAAlPUb$bA!f&amp;quot;3_&amp;gt;&lt;/code>
И расшифровываю ее&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">st &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#34;t2f&lt;/span>&lt;span style="color:#ae81ff">\\&lt;/span>&lt;span style="color:#e6db74">iDAAlPUb$bA!f&lt;/span>&lt;span style="color:#ae81ff">\&amp;#34;&lt;/span>&lt;span style="color:#e6db74">3_&amp;gt;&amp;#34;&lt;/span>
res &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(len(st)):
res &lt;span style="color:#f92672">+=&lt;/span> chr(ord(st[i]) &lt;span style="color:#f92672">+&lt;/span> i)
print(res) &lt;span style="color:#75715e"># t3h_mIGHtY_m0oO0v3ErR&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>А кто-то говорил, что стега от менада ничему не учит&amp;hellip;&lt;/p>
&lt;h2 id="check-summer">Check Summer&lt;/h2>
&lt;p>К бинарю на паскале прилагается трасса инструкций вида&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-asm" data-lang="asm">&lt;span style="color:#960050;background-color:#1e0010">004216&lt;/span>&lt;span style="color:#a6e22e">CF&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">CALL&lt;/span> &lt;span style="color:#66d9ef">check_su.0040D760&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D760&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">PUSH&lt;/span> &lt;span style="color:#66d9ef">EBX&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D761&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">MOV&lt;/span> &lt;span style="color:#66d9ef">EDX&lt;/span>,&lt;span style="color:#66d9ef">DWORD&lt;/span> &lt;span style="color:#66d9ef">PTR&lt;/span> &lt;span style="color:#66d9ef">DS&lt;/span>:[&lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#66d9ef">CC020&lt;/span>]
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D767&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">TEST&lt;/span> &lt;span style="color:#66d9ef">EDX&lt;/span>,&lt;span style="color:#66d9ef">EDX&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D769&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">JE&lt;/span> &lt;span style="color:#66d9ef">SHORT&lt;/span> &lt;span style="color:#66d9ef">check_su.0040D776&lt;/span>
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D76B&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">MOV&lt;/span> &lt;span style="color:#66d9ef">EAX&lt;/span>,&lt;span style="color:#66d9ef">DWORD&lt;/span> &lt;span style="color:#66d9ef">PTR&lt;/span> &lt;span style="color:#66d9ef">DS&lt;/span>:[&lt;span style="color:#ae81ff">5&lt;/span>&lt;span style="color:#66d9ef">CB320&lt;/span>]
&lt;span style="color:#960050;background-color:#1e0010">0040&lt;/span>&lt;span style="color:#a6e22e">D770&lt;/span> &lt;span style="color:#66d9ef">Main&lt;/span> &lt;span style="color:#66d9ef">CALL&lt;/span> &lt;span style="color:#66d9ef">EDX&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Логику работы бинарника за меня опишет эта гифка:&lt;/p>
&lt;p>&lt;img src="https://rev-kids20.forkbomb.ru/files/rev/newX/check_summer_screen.gif" alt="">&lt;/p>
&lt;p>По xref-ам находим алгоритм создания хеша от флага&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/ziQ6e5j.png" alt="">&lt;/p>
&lt;p>И сам алгоритм хеширования:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#66d9ef">int&lt;/span> __usercall UNIT1____CRC32_ANSISTRING__ANSISTRING&lt;span style="color:#960050;background-color:#1e0010">@&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>eax&lt;span style="color:#f92672">&amp;gt;&lt;/span>(&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">__int8&lt;/span> &lt;span style="color:#f92672">*&lt;/span>input&lt;span style="color:#960050;background-color:#1e0010">@&lt;/span>&lt;span style="color:#f92672">&amp;lt;&lt;/span>eax&lt;span style="color:#f92672">&amp;gt;&lt;/span>)
{
&lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> state, length; &lt;span style="color:#75715e">// ebx
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">unsigned&lt;/span> &lt;span style="color:#66d9ef">__int8&lt;/span> &lt;span style="color:#f92672">*&lt;/span>inp; &lt;span style="color:#75715e">// [esp+38h] [ebp-4h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
inp &lt;span style="color:#f92672">=&lt;/span> input; &lt;span style="color:#75715e">// адрес - 0x04244B0
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#75715e">// ...
&lt;/span>&lt;span style="color:#75715e">&lt;/span> v7 &lt;span style="color:#f92672">=&lt;/span> FPC_SETJMP();
&lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!&lt;/span>v7 )
{
state &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0xFFFFFFFF&lt;/span>;
length &lt;span style="color:#f92672">=&lt;/span> (&lt;span style="color:#66d9ef">int&lt;/span>)inp;
&lt;span style="color:#66d9ef">if&lt;/span> ( inp )
length &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#f92672">*&lt;/span>((_DWORD &lt;span style="color:#f92672">*&lt;/span>)inp &lt;span style="color:#f92672">-&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>);
&lt;span style="color:#66d9ef">if&lt;/span> ( length &lt;span style="color:#f92672">&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> )
{
inp_i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;span style="color:#66d9ef">do&lt;/span>
{
state &lt;span style="color:#f92672">^=&lt;/span> inp[inp_i&lt;span style="color:#f92672">++&lt;/span>]; &lt;span style="color:#75715e">// 0x0424507
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">for&lt;/span> ( i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span>; i &lt;span style="color:#f92672">&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; &lt;span style="color:#f92672">--&lt;/span>i )
{
&lt;span style="color:#66d9ef">if&lt;/span> ( (state &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> ) &lt;span style="color:#75715e">// если state нечетное
&lt;/span>&lt;span style="color:#75715e">&lt;/span> state &lt;span style="color:#f92672">=&lt;/span> (state &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">0xEDB88320&lt;/span>; &lt;span style="color:#75715e">// адрес - 0x0424519
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#75715e">// четное
&lt;/span>&lt;span style="color:#75715e">&lt;/span> state &lt;span style="color:#f92672">&amp;gt;&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>; &lt;span style="color:#75715e">// адрес - 0x0424527
&lt;/span>&lt;span style="color:#75715e">&lt;/span> }
}
&lt;span style="color:#66d9ef">while&lt;/span> ( length &lt;span style="color:#f92672">&amp;gt;&lt;/span> inp_i );
}
SYSUTILS____INTTOHEX_QWORD_LONGINT__ANSISTRING(&lt;span style="color:#f92672">~&lt;/span>state, &lt;span style="color:#ae81ff">0&lt;/span>);
}
&lt;span style="color:#75715e">// ...
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> state; &lt;span style="color:#75715e">// адрес - 0x0424568
&lt;/span>&lt;span style="color:#75715e">&lt;/span>}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Идея моего решения состоит в том, чтобы по четности стейта и его значению на предыдущей итерации цикла &lt;code>while&lt;/code>, определить символ, с которым стейт был поксорен.&lt;/p>
&lt;p>Финальный код решения:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">data &lt;span style="color:#f92672">=&lt;/span> open(&lt;span style="color:#e6db74">&amp;#39;check_summer_rtrace.txt&amp;#39;&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>read()&lt;span style="color:#f92672">.&lt;/span>split(&lt;span style="color:#e6db74">&amp;#39;&lt;/span>&lt;span style="color:#ae81ff">\n&lt;/span>&lt;span style="color:#e6db74">&amp;#39;&lt;/span>)[:&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]
addrs &lt;span style="color:#f92672">=&lt;/span> [i&lt;span style="color:#f92672">.&lt;/span>split()[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> data]
start_crc_func &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;004244B0&amp;#39;&lt;/span> &lt;span style="color:#75715e"># начало функции&lt;/span>
end_crc_func &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;00424568&amp;#39;&lt;/span> &lt;span style="color:#75715e"># конец функции &lt;/span>
xor_state_addr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;00424507&amp;#39;&lt;/span> &lt;span style="color:#75715e"># state ^= inp[inp_i++]&lt;/span>
is_state_odd_addr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;00424519&amp;#39;&lt;/span> &lt;span style="color:#75715e"># state = (state &amp;gt;&amp;gt; 1) ^ 0xEDB88320&lt;/span>
is_state_even_addr &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;00424527&amp;#39;&lt;/span> &lt;span style="color:#75715e"># state &amp;gt;&amp;gt;= 1&lt;/span>
addrs &lt;span style="color:#f92672">=&lt;/span> addrs[addrs&lt;span style="color:#f92672">.&lt;/span>index(end_crc_func)&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>:] &lt;span style="color:#75715e"># на гифке видно, что при снятии трассы хеш берется 2 раза (от слова SPbCTF и от флага), нам нужен именно последний , поэтому отбрасываем часть трассы с хешированием SPbCTF&lt;/span>
func_block &lt;span style="color:#f92672">=&lt;/span> addrs[addrs&lt;span style="color:#f92672">.&lt;/span>index(start_crc_func):addrs&lt;span style="color:#f92672">.&lt;/span>index(end_crc_func)]
check_arr &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">for&lt;/span> addr &lt;span style="color:#f92672">in&lt;/span> func_block:
&lt;span style="color:#66d9ef">if&lt;/span> addr &lt;span style="color:#f92672">==&lt;/span> is_state_odd_addr:
check_arr&lt;span style="color:#f92672">.&lt;/span>append(&lt;span style="color:#ae81ff">1&lt;/span>)
&lt;span style="color:#66d9ef">elif&lt;/span> addr &lt;span style="color:#f92672">==&lt;/span> is_state_even_addr:
check_arr&lt;span style="color:#f92672">.&lt;/span>append(&lt;span style="color:#ae81ff">0&lt;/span>)
state_prev &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0xFFFFFFFF&lt;/span>
flag &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>
&lt;span style="color:#75715e"># длину флага находим по кол-ву совершенных state ^= inp[inp_i++]&lt;/span>
flag_len &lt;span style="color:#f92672">=&lt;/span> func_block&lt;span style="color:#f92672">.&lt;/span>count(xor_state_addr)
&lt;span style="color:#66d9ef">for&lt;/span> inp_i &lt;span style="color:#f92672">in&lt;/span> range(flag_len):
&lt;span style="color:#66d9ef">for&lt;/span> char &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">32&lt;/span>,&lt;span style="color:#ae81ff">127&lt;/span>):
state &lt;span style="color:#f92672">=&lt;/span> state_prev &lt;span style="color:#f92672">^&lt;/span> char
new_state_check_arr &lt;span style="color:#f92672">=&lt;/span> []
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">8&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> (state &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>:
new_state_check_arr&lt;span style="color:#f92672">.&lt;/span>append(&lt;span style="color:#ae81ff">1&lt;/span>)
state &lt;span style="color:#f92672">=&lt;/span> (state &lt;span style="color:#f92672">&amp;gt;&amp;gt;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">^&lt;/span> &lt;span style="color:#ae81ff">0xEDB88320&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
new_state_check_arr&lt;span style="color:#f92672">.&lt;/span>append(&lt;span style="color:#ae81ff">0&lt;/span>)
state &lt;span style="color:#f92672">&amp;gt;&amp;gt;=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span> new_state_check_arr &lt;span style="color:#f92672">==&lt;/span> check_arr[inp_i&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">8&lt;/span>:inp_i&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">8&lt;/span>&lt;span style="color:#f92672">+&lt;/span>&lt;span style="color:#ae81ff">8&lt;/span>]:
state_prev &lt;span style="color:#f92672">=&lt;/span> state
flag &lt;span style="color:#f92672">+=&lt;/span> chr(char)
&lt;span style="color:#66d9ef">break&lt;/span>
print(flag)
&lt;span style="color:#75715e"># spbctf{June_1st_it5_r34lly_sUmm3R}&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>- https://uvicorn.github.io/posts/forkbomb_ch2-writeup/ -</description></item><item><title>Forkbomb reverse ch1</title><link>https://uvicorn.github.io/posts/forkbomb_ch1-writeup/</link><pubDate>Mon, 31 Jan 2022 04:55:00 +0700</pubDate><guid>https://uvicorn.github.io/posts/forkbomb_ch1-writeup/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/forkbomb_ch1-writeup/ -&lt;h2 id="lemballovo">Lemballovo&lt;/h2>
&lt;p>Запускаем игру и ловим непонятную ошибку:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/LHKb3NF.png" alt="">&lt;/p>
&lt;p>Закидываем бинарь в иду и по xref-ам находим место, где вылетает ошибка:
&lt;img src="https://uvicorn.github.io/images/mZeviyh.png" alt="">&lt;/p>
&lt;p>Патчим на&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/4NmXkdz.png" alt="">&lt;/p>
&lt;p>И, о чудо, нас ждет уже другая ошибка&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/AdA9yzZ.png" alt="">&lt;/p>
&lt;p>Запатчив игру еще пару раз подобным образом, она заработает и выдаст флаг.&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/cBiiNjm.png" alt="">&lt;/p>
&lt;p>Полный список адресов, по которым нужно запатчить:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/DR4G79Q.png" alt="">&lt;/p>
&lt;h2 id="httpsec">httpsec&lt;/h2>
&lt;p>Пропрыгав по xref-ам находим алгоритм получения флага:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-c" data-lang="c">&lt;span style="color:#66d9ef">int&lt;/span> &lt;span style="color:#a6e22e">sub_138D&lt;/span>()
{
&lt;span style="color:#66d9ef">int&lt;/span> v1; &lt;span style="color:#75715e">// eax
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v2; &lt;span style="color:#75715e">// eax
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> v3[&lt;span style="color:#ae81ff">136&lt;/span>]; &lt;span style="color:#75715e">// [rsp+0h] [rbp-C0h] BYREF
&lt;/span>&lt;span style="color:#75715e">&lt;/span> FILE &lt;span style="color:#f92672">*&lt;/span>stream; &lt;span style="color:#75715e">// [rsp+88h] [rbp-38h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v5; &lt;span style="color:#75715e">// [rsp+94h] [rbp-2Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">char&lt;/span> &lt;span style="color:#f92672">*&lt;/span>check_st; &lt;span style="color:#75715e">// [rsp+98h] [rbp-28h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> i; &lt;span style="color:#75715e">// [rsp+A4h] [rbp-1Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> res; &lt;span style="color:#75715e">// [rsp+A8h] [rbp-18h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v9; &lt;span style="color:#75715e">// [rsp+ACh] [rbp-14h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v10; &lt;span style="color:#75715e">// [rsp+B0h] [rbp-10h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v11; &lt;span style="color:#75715e">// [rsp+B4h] [rbp-Ch]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v12; &lt;span style="color:#75715e">// [rsp+B8h] [rbp-8h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span> v13; &lt;span style="color:#75715e">// [rsp+BCh] [rbp-4h]
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">if&lt;/span> ( &lt;span style="color:#f92672">!&lt;/span>strcmp(&lt;span style="color:#e6db74">&amp;#34;/&amp;#34;&lt;/span>, s2) &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#f92672">!&lt;/span>strcmp(&lt;span style="color:#e6db74">&amp;#34;GET&amp;#34;&lt;/span>, http_method) )
{
puts(&lt;span style="color:#e6db74">&amp;#34;HTTP/1.1 200 OK&lt;/span>&lt;span style="color:#ae81ff">\r\n\r&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
&lt;span style="color:#66d9ef">return&lt;/span> puts(&lt;span style="color:#e6db74">&amp;#34;Welcome to our fast web-server&lt;/span>&lt;span style="color:#ae81ff">\r&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
}
&lt;span style="color:#66d9ef">else&lt;/span> &lt;span style="color:#66d9ef">if&lt;/span> ( strcmp(s2, &lt;span style="color:#e6db74">&amp;#34;/secret/&amp;#34;&lt;/span>) &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span> &lt;span style="color:#f92672">&amp;amp;&amp;amp;&lt;/span> &lt;span style="color:#f92672">!&lt;/span>strcmp(&lt;span style="color:#e6db74">&amp;#34;GET&amp;#34;&lt;/span>, http_method) )
{
check_st &lt;span style="color:#f92672">=&lt;/span> get_header_content(&lt;span style="color:#e6db74">&amp;#34;X-Auth&amp;#34;&lt;/span>);
&lt;span style="color:#66d9ef">if&lt;/span> ( check_st )
{
st_len &lt;span style="color:#f92672">=&lt;/span> strlen(check_st);
&lt;span style="color:#66d9ef">if&lt;/span> ( st_len &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">8&lt;/span> )
{
v13 &lt;span style="color:#f92672">=&lt;/span> check_st[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> &lt;span style="color:#f92672">*&lt;/span>check_st &lt;span style="color:#f92672">-&lt;/span> check_st[&lt;span style="color:#ae81ff">6&lt;/span>];
v12 &lt;span style="color:#f92672">=&lt;/span> check_st[&lt;span style="color:#ae81ff">6&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> check_st[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> check_st[&lt;span style="color:#ae81ff">2&lt;/span>];
v11 &lt;span style="color:#f92672">=&lt;/span> check_st[&lt;span style="color:#ae81ff">7&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> check_st[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> check_st[&lt;span style="color:#ae81ff">3&lt;/span>];
v10 &lt;span style="color:#f92672">=&lt;/span> check_st[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> check_st[&lt;span style="color:#ae81ff">5&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> check_st[&lt;span style="color:#ae81ff">7&lt;/span>];
v9 &lt;span style="color:#f92672">=&lt;/span> check_st[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> check_st[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> check_st[&lt;span style="color:#ae81ff">2&lt;/span>];
res &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>;
&lt;span style="color:#66d9ef">for&lt;/span> ( i &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>; i &lt;span style="color:#f92672">&amp;lt;=&lt;/span> &lt;span style="color:#ae81ff">7&lt;/span>; &lt;span style="color:#f92672">++&lt;/span>i )
{
&lt;span style="color:#66d9ef">if&lt;/span> ( (v12 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> )
{
v10 &lt;span style="color:#f92672">-=&lt;/span> v13;
&lt;span style="color:#66d9ef">if&lt;/span> ( (v10 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> )
{
v11 &lt;span style="color:#f92672">-=&lt;/span> v9;
v2 &lt;span style="color:#f92672">=&lt;/span> v12 &lt;span style="color:#f92672">+&lt;/span> v13;
}
&lt;span style="color:#66d9ef">else&lt;/span>
{
v12 &lt;span style="color:#f92672">-=&lt;/span> v9;
v2 &lt;span style="color:#f92672">=&lt;/span> v11 &lt;span style="color:#f92672">+&lt;/span> v12;
}
res &lt;span style="color:#f92672">+=&lt;/span> v2;
}
&lt;span style="color:#66d9ef">else&lt;/span>
{
v9 &lt;span style="color:#f92672">-=&lt;/span> v11;
&lt;span style="color:#66d9ef">if&lt;/span> ( (v13 &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> )
{
v13 &lt;span style="color:#f92672">-=&lt;/span> v12;
v1 &lt;span style="color:#f92672">=&lt;/span> v10 &lt;span style="color:#f92672">+&lt;/span> v9;
}
&lt;span style="color:#66d9ef">else&lt;/span>
{
v10 &lt;span style="color:#f92672">-=&lt;/span> v11;
v1 &lt;span style="color:#f92672">=&lt;/span> v13 &lt;span style="color:#f92672">+&lt;/span> v12;
}
res &lt;span style="color:#f92672">+=&lt;/span> v1;
}
v13 &lt;span style="color:#f92672">^=&lt;/span> v12;
v12 &lt;span style="color:#f92672">^=&lt;/span> v11;
v11 &lt;span style="color:#f92672">^=&lt;/span> v10;
v10 &lt;span style="color:#f92672">^=&lt;/span> v9;
v9 &lt;span style="color:#f92672">^=&lt;/span> v13;
}
&lt;span style="color:#66d9ef">if&lt;/span> ( res &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">444&lt;/span> )
{
stream &lt;span style="color:#f92672">=&lt;/span> fopen(&lt;span style="color:#e6db74">&amp;#34;flag.txt&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;r&amp;#34;&lt;/span>);
fgets(v3, &lt;span style="color:#ae81ff">128&lt;/span>, stream);
fclose(stream);
puts(&lt;span style="color:#e6db74">&amp;#34;HTTP/1.1 200 OK&lt;/span>&lt;span style="color:#ae81ff">\r\n\r&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>);
&lt;span style="color:#66d9ef">return&lt;/span> printf(&lt;span style="color:#e6db74">&amp;#34;Flag: %s&lt;/span>&lt;span style="color:#ae81ff">\r\n&lt;/span>&lt;span style="color:#e6db74">&amp;#34;&lt;/span>, v3);
}
}
}
}
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Попытка решить все это дело с помощью z3 не увенчалась успехом, поэтому пришлось брутить:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> requests&lt;span style="color:#f92672">,&lt;/span>random
arr &lt;span style="color:#f92672">=&lt;/span> [&lt;span style="color:#ae81ff">0&lt;/span>]&lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#ae81ff">5&lt;/span>
&lt;span style="color:#66d9ef">while&lt;/span> &lt;span style="color:#66d9ef">True&lt;/span>:
st &lt;span style="color:#f92672">=&lt;/span> [random&lt;span style="color:#f92672">.&lt;/span>randint(&lt;span style="color:#ae81ff">32&lt;/span>,&lt;span style="color:#ae81ff">126&lt;/span>) &lt;span style="color:#66d9ef">for&lt;/span> _ &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">8&lt;/span>)]
arr[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> st[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> st[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> st[&lt;span style="color:#ae81ff">6&lt;/span>]
arr[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> st[&lt;span style="color:#ae81ff">6&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> st[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> st[&lt;span style="color:#ae81ff">2&lt;/span>]
arr[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> st[&lt;span style="color:#ae81ff">7&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> st[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> st[&lt;span style="color:#ae81ff">3&lt;/span>]
arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> st[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> st[&lt;span style="color:#ae81ff">5&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> st[&lt;span style="color:#ae81ff">7&lt;/span>]
arr[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> st[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> st[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-&lt;/span> st[&lt;span style="color:#ae81ff">2&lt;/span>]
check_var_444 &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> i &lt;span style="color:#f92672">in&lt;/span> range(&lt;span style="color:#ae81ff">8&lt;/span>):
&lt;span style="color:#66d9ef">if&lt;/span> ( (arr[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> ):
arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">4&lt;/span>]
&lt;span style="color:#66d9ef">if&lt;/span> ( (arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> ):
arr[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">0&lt;/span>]
v1 &lt;span style="color:#f92672">=&lt;/span> arr[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> arr[&lt;span style="color:#ae81ff">4&lt;/span>]
&lt;span style="color:#66d9ef">else&lt;/span>:
arr[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">0&lt;/span>]
v1 &lt;span style="color:#f92672">=&lt;/span> arr[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> arr[&lt;span style="color:#ae81ff">3&lt;/span>]
&lt;span style="color:#66d9ef">else&lt;/span>:
arr[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">2&lt;/span>];
&lt;span style="color:#66d9ef">if&lt;/span> ( (arr[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">&amp;amp;&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">0&lt;/span> ):
arr[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">3&lt;/span>]
v1 &lt;span style="color:#f92672">=&lt;/span> arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> arr[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;span style="color:#66d9ef">else&lt;/span>:
arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">-=&lt;/span> arr[&lt;span style="color:#ae81ff">2&lt;/span>];
v1 &lt;span style="color:#f92672">=&lt;/span> arr[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">+&lt;/span> arr[&lt;span style="color:#ae81ff">3&lt;/span>]
check_var_444 &lt;span style="color:#f92672">+=&lt;/span> v1
arr[&lt;span style="color:#ae81ff">4&lt;/span>] &lt;span style="color:#f92672">^=&lt;/span> arr[&lt;span style="color:#ae81ff">3&lt;/span>]
arr[&lt;span style="color:#ae81ff">3&lt;/span>] &lt;span style="color:#f92672">^=&lt;/span> arr[&lt;span style="color:#ae81ff">2&lt;/span>]
arr[&lt;span style="color:#ae81ff">2&lt;/span>] &lt;span style="color:#f92672">^=&lt;/span> arr[&lt;span style="color:#ae81ff">1&lt;/span>]
arr[&lt;span style="color:#ae81ff">1&lt;/span>] &lt;span style="color:#f92672">^=&lt;/span> arr[&lt;span style="color:#ae81ff">0&lt;/span>]
arr[&lt;span style="color:#ae81ff">0&lt;/span>] &lt;span style="color:#f92672">^=&lt;/span> arr[&lt;span style="color:#ae81ff">4&lt;/span>]
&lt;span style="color:#66d9ef">if&lt;/span> check_var_444 &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">444&lt;/span>:
print(requests&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;http://109.233.56.90:11544/secret/&amp;#39;&lt;/span>,headers &lt;span style="color:#f92672">=&lt;/span> {&lt;span style="color:#e6db74">&amp;#34;X-Auth&amp;#34;&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>&lt;span style="color:#f92672">.&lt;/span>join(map(chr,st))})&lt;span style="color:#f92672">.&lt;/span>content)
&lt;span style="color:#66d9ef">break&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>P.S.: Нужно было сразу брутфорсить, а не загонять в z3, но я подумал, что брутить будет слишком долго. Вот так неверная оценка сложности шифрования может привести к нескольким потерянным часам.&lt;/p>
&lt;h2 id="gython">Gython&lt;/h2>
&lt;p>&lt;del>О нет голанг&lt;/del> Закидываем в иду и наслаждаемся псевдокодом.
&lt;img src="https://uvicorn.github.io/images/rtR4kVr.png" alt="">&lt;/p>
&lt;p>Алгоритм работы бинаря прост - дропнуть &lt;code>__init__.pyc&lt;/code> на диск и запустить ее (в агрументах при этом передается что-то похожее на ключ - &lt;code>HzURFvGeN7sClEVLJDBnZVnlrTUBDw41RFefNmcB7bdfFg==&lt;/code>).&lt;/p>
&lt;p>Вытащить адрес проживания пики можно strace-ом:
&lt;img src="https://uvicorn.github.io/images/aSXQAEw.png" alt="">&lt;/p>
&lt;p>Декомпилируем пику и получаем следующие:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> base64&lt;span style="color:#f92672">,&lt;/span> hashlib&lt;span style="color:#f92672">,&lt;/span> os&lt;span style="color:#f92672">,&lt;/span> sys&lt;span style="color:#f92672">,&lt;/span> urllib.request
KEY &lt;span style="color:#f92672">=&lt;/span> &lt;span style="color:#e6db74">b&lt;/span>&lt;span style="color:#e6db74">&amp;#39;K[&lt;/span>&lt;span style="color:#ae81ff">\x87\xb7\xdd&lt;/span>&lt;span style="color:#e6db74">R&lt;/span>&lt;span style="color:#ae81ff">\x1e\xc0&lt;/span>&lt;span style="color:#e6db74">I&lt;/span>&lt;span style="color:#ae81ff">\x1d&lt;/span>&lt;span style="color:#e6db74">/&lt;/span>&lt;span style="color:#ae81ff">\xa2\xea\xa4\xad&lt;/span>&lt;span style="color:#e6db74">GW?Z&lt;/span>&lt;span style="color:#ae81ff">\xff&lt;/span>&lt;span style="color:#e6db74">N&lt;/span>&lt;span style="color:#ae81ff">\x80&lt;/span>&lt;span style="color:#e6db74">k&lt;/span>&lt;span style="color:#ae81ff">\x9d\xe1\xfc&lt;/span>&lt;span style="color:#e6db74">4&lt;/span>&lt;span style="color:#ae81ff">\xff&lt;/span>&lt;span style="color:#e6db74">s&lt;/span>&lt;span style="color:#ae81ff">\xb2\x86&lt;/span>&lt;span style="color:#e6db74">k1&amp;#39;&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">byte_xor&lt;/span>(ba1, ba2):
&lt;span style="color:#66d9ef">return&lt;/span> bytes([_a &lt;span style="color:#f92672">^&lt;/span> _b &lt;span style="color:#66d9ef">for&lt;/span> _a, _b &lt;span style="color:#f92672">in&lt;/span> zip(ba1, ba2)])
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">encrypt&lt;/span>(key, plaintext):
&lt;span style="color:#66d9ef">while&lt;/span> len(key) &lt;span style="color:#f92672">&amp;lt;&lt;/span> len(plaintext):
key &lt;span style="color:#f92672">+=&lt;/span> hashlib&lt;span style="color:#f92672">.&lt;/span>sha256(key)&lt;span style="color:#f92672">.&lt;/span>digest()
key &lt;span style="color:#f92672">=&lt;/span> key[::&lt;span style="color:#f92672">-&lt;/span>&lt;span style="color:#ae81ff">1&lt;/span>]
&lt;span style="color:#66d9ef">return&lt;/span> byte_xor(key[:len(plaintext)], plaintext)
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">check&lt;/span>(params):
&lt;span style="color:#66d9ef">if&lt;/span> len(params) &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">False&lt;/span>
&lt;span style="color:#66d9ef">else&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> hashlib&lt;span style="color:#f92672">.&lt;/span>sha256(encrypt(KEY, base64&lt;span style="color:#f92672">.&lt;/span>b64decode(params[&lt;span style="color:#ae81ff">0&lt;/span>])))&lt;span style="color:#f92672">.&lt;/span>hexdigest() &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#e6db74">&amp;#39;fb0d5faa2b54bc25b1654a90106913bd1dd7e5a0400986f7676ec1e0afa93d71&amp;#39;&lt;/span>
&lt;span style="color:#66d9ef">try&lt;/span>:
&lt;span style="color:#66d9ef">if&lt;/span> check(sys&lt;span style="color:#f92672">.&lt;/span>argv[&lt;span style="color:#ae81ff">1&lt;/span>:]):
r &lt;span style="color:#f92672">=&lt;/span> urllib&lt;span style="color:#f92672">.&lt;/span>request&lt;span style="color:#f92672">.&lt;/span>urlopen(&lt;span style="color:#e6db74">&amp;#39;https://forkbomb.ru/?answer=&amp;#39;&lt;/span> &lt;span style="color:#f92672">+&lt;/span> str(encrypt(KEY, str(os&lt;span style="color:#f92672">.&lt;/span>getuid())&lt;span style="color:#f92672">.&lt;/span>encode())))
&lt;span style="color:#66d9ef">with&lt;/span> open(&lt;span style="color:#e6db74">&amp;#39;1.txt&amp;#39;&lt;/span>, &lt;span style="color:#e6db74">&amp;#39;w&amp;#39;&lt;/span>) &lt;span style="color:#66d9ef">as&lt;/span> (f):
f&lt;span style="color:#f92672">.&lt;/span>write(r&lt;span style="color:#f92672">.&lt;/span>read(&lt;span style="color:#ae81ff">1024&lt;/span>)&lt;span style="color:#f92672">.&lt;/span>decode(&lt;span style="color:#e6db74">&amp;#39;utf-8&amp;#39;&lt;/span>))
&lt;span style="color:#66d9ef">except&lt;/span>:
&lt;span style="color:#66d9ef">pass&lt;/span>
&lt;span style="color:#66d9ef">with&lt;/span> open(__file__, &lt;span style="color:#e6db74">&amp;#39;wb&amp;#39;&lt;/span>) &lt;span style="color:#66d9ef">as&lt;/span> (f):
f&lt;span style="color:#f92672">.&lt;/span>write(&lt;span style="color:#e6db74">&amp;#39;&amp;#39;&lt;/span>)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>В check передаются argv, то есть тот странный ключ.&lt;/p>
&lt;p>На этом моменте я долго тупил и не понимал куда идти дальше. Спустя пару дней решение пришло само собой:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">encrypt(KEY, base64&lt;span style="color:#f92672">.&lt;/span>b64decode(&lt;span style="color:#e6db74">&amp;#39;HzURFvGeN7sClEVLJDBnZVnlrTUBDw41RFefNmcB7bdfFg==&amp;#39;&lt;/span>))
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="speedreading">Speedreading&lt;/h2>
&lt;p>Задача состоит в получении премиум доступа в приложении для Андроида.&lt;/p>
&lt;p>Исследование апк в jadx заводит в &lt;code>com.safonov.speedreading.application.util.PremiumUtil&lt;/code>:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/30IQ4hA.png" alt="">&lt;/p>
&lt;p>Видно, что уровень доступа(премиум или нет) проверяется только на клиенте, соответственно мы можем запатчить этот самый клиент.&lt;/p>
&lt;p>Извлечем байткод из &lt;code>classes.dex&lt;/code>, который находится внутри апк: &lt;code>apktool d ./SpeedRead.apk&lt;/code>.&lt;/p>
&lt;p>Откроем &lt;code>PremiumUtil.smali&lt;/code> и изменим код функции &lt;code>isPremiumUser&lt;/code> с&lt;/p>
&lt;pre tabindex="0">&lt;code>.method public isPremiumUser()Z
.locals 1
.prologue
.line 22
iget-boolean v0, p0, Lcom/safonov/speedreading/application/util/PremiumUtil;-&amp;gt;premiumUser:Z
return v0
.end method
&lt;/code>&lt;/pre>&lt;p>На&lt;/p>
&lt;pre tabindex="0">&lt;code>.method public isPremiumUser()Z
.locals 1
.prologue
.line 22
const/4 v0, 0x1 # v0 = true
return v0
.end method
&lt;/code>&lt;/pre>&lt;p>Пересоберем приложение: &lt;code>apktool b ./SpeedRead -o SpeedRead_Patched.apk&lt;/code>&lt;/p>
&lt;p>Запускаем приложение и получаем желаемое:&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/1rCw4Ny.png" alt="">&lt;/p>
- https://uvicorn.github.io/posts/forkbomb_ch1-writeup/ -</description></item><item><title>Sad Rendel</title><link>https://uvicorn.github.io/posts/sad-rendel-writeup/</link><pubDate>Tue, 30 Nov 2021 04:20:25 +0700</pubDate><guid>https://uvicorn.github.io/posts/sad-rendel-writeup/</guid><description>Uvicorn blog https://uvicorn.github.io/posts/sad-rendel-writeup/ -&lt;p>&lt;a href="http://sad-rendel.tasks.2021.ctf.cs.msu.ru">&lt;del>Ссылка на таск&lt;/del> без vpn конфига не работает&lt;/a>&lt;/p>
&lt;p>&lt;a href="https://github.com/uvicorn/writeups/tree/master/Sad_Rendel/app">И его сорцы&lt;/a>&lt;/p>
&lt;h2 id="немного-истории">Немного истории&lt;/h2>
&lt;p>Таск был взят с &lt;a href="https://2021.ctf.cs.msu.ru/challenges">Moscow School Ctf 2021&lt;/a>, на которой я играл в команде Shadow Kitties (8 место).&lt;/p>
&lt;p>Удивлен, что его решило всего 2 команды.
&lt;img src="https://uvicorn.github.io/images/9UWiDLf.png" alt="">
Решил я только этот таск.
В свое оправдание скажу, что в тот день писал олимпиаду Верченко по криптографии, пол дня провел в городе и приехал домой мертвый.&lt;/p>
&lt;h2 id="решение">Решение&lt;/h2>
&lt;p>Заглянем в &lt;a href="https://github.com/uvicorn/writeups/blob/master/Sad_Rendel/app/main.py">main.py&lt;/a> и обнаружим условие получения флага.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">from&lt;/span> cookies &lt;span style="color:#f92672">import&lt;/span> encrypt_cookie, decrypt_cookie
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">get_user&lt;/span>(request):
cookie &lt;span style="color:#f92672">=&lt;/span> request&lt;span style="color:#f92672">.&lt;/span>cookies&lt;span style="color:#f92672">.&lt;/span>get(&lt;span style="color:#e6db74">&amp;#39;sess&amp;#39;&lt;/span>)
&lt;span style="color:#66d9ef">if&lt;/span> cookie &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>
session_data &lt;span style="color:#f92672">=&lt;/span> decrypt_cookie(cookie)
&lt;span style="color:#66d9ef">return&lt;/span> int(session_data[&lt;span style="color:#e6db74">&amp;#34;user_id&amp;#34;&lt;/span>])
&lt;span style="color:#66d9ef">async&lt;/span> &lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">get_flag&lt;/span>(request):
user &lt;span style="color:#f92672">=&lt;/span> get_user(request)
&lt;span style="color:#66d9ef">if&lt;/span> user &lt;span style="color:#f92672">is&lt;/span> &lt;span style="color:#66d9ef">None&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> templates&lt;span style="color:#f92672">.&lt;/span>TemplateResponse(&lt;span style="color:#e6db74">&amp;#39;flag_page.html&amp;#39;&lt;/span>, {
&lt;span style="color:#e6db74">&amp;#39;request&amp;#39;&lt;/span>: request,
&lt;span style="color:#e6db74">&amp;#39;flag&amp;#39;&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;Flag is not available to anonymous users&amp;#39;&lt;/span>
})
&lt;span style="color:#66d9ef">if&lt;/span> user &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> templates&lt;span style="color:#f92672">.&lt;/span>TemplateResponse(&lt;span style="color:#e6db74">&amp;#39;flag_page.html&amp;#39;&lt;/span>, {
&lt;span style="color:#e6db74">&amp;#39;request&amp;#39;&lt;/span>: request,
&lt;span style="color:#e6db74">&amp;#39;flag&amp;#39;&lt;/span>: FLAG
})
&lt;span style="color:#66d9ef">else&lt;/span>:
&lt;span style="color:#66d9ef">return&lt;/span> templates&lt;span style="color:#f92672">.&lt;/span>TemplateResponse(&lt;span style="color:#e6db74">&amp;#39;flag_page.html&amp;#39;&lt;/span>, {
&lt;span style="color:#e6db74">&amp;#39;request&amp;#39;&lt;/span>: request,
&lt;span style="color:#e6db74">&amp;#39;flag&amp;#39;&lt;/span>: &lt;span style="color:#e6db74">&amp;#39;Only admin can read a flag&amp;#39;&lt;/span>
})
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Разобравшись, что get_user берет информацию о пользователе из куки и возвращает его user_id, используя при этом функцию decrypt_cookie, идем в &lt;a href="https://github.com/uvicorn/writeups/blob/master/Sad_Rendel/app/cookies.py">cookies.py&lt;/a> к этой самой функции.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">decrypt_cookie&lt;/span>(encrypted_cookie):
envelope_data &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>loads(base64&lt;span style="color:#f92672">.&lt;/span>b64decode(encrypted_cookie))
iv &lt;span style="color:#f92672">=&lt;/span> base64&lt;span style="color:#f92672">.&lt;/span>b64decode(envelope_data[&lt;span style="color:#e6db74">&amp;#39;iv&amp;#39;&lt;/span>])
cbc &lt;span style="color:#f92672">=&lt;/span> AES&lt;span style="color:#f92672">.&lt;/span>new(KEY2, AES&lt;span style="color:#f92672">.&lt;/span>MODE_CBC, iv)
second_layer &lt;span style="color:#f92672">=&lt;/span> base64&lt;span style="color:#f92672">.&lt;/span>b64decode(envelope_data[&lt;span style="color:#e6db74">&amp;#39;data&amp;#39;&lt;/span>])
first_layer &lt;span style="color:#f92672">=&lt;/span> cbc&lt;span style="color:#f92672">.&lt;/span>decrypt(second_layer)
nonce &lt;span style="color:#f92672">=&lt;/span> base64&lt;span style="color:#f92672">.&lt;/span>b64decode(envelope_data[&lt;span style="color:#e6db74">&amp;#39;nonce&amp;#39;&lt;/span>])
ctr &lt;span style="color:#f92672">=&lt;/span> AES&lt;span style="color:#f92672">.&lt;/span>new(KEY1, AES&lt;span style="color:#f92672">.&lt;/span>MODE_CTR, nonce&lt;span style="color:#f92672">=&lt;/span>nonce)
data &lt;span style="color:#f92672">=&lt;/span> ctr&lt;span style="color:#f92672">.&lt;/span>decrypt(first_layer)
&lt;span style="color:#66d9ef">return&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>JSONDecoder()&lt;span style="color:#f92672">.&lt;/span>raw_decode(data&lt;span style="color:#f92672">.&lt;/span>decode(&lt;span style="color:#e6db74">&amp;#39;utf8&amp;#39;&lt;/span>, errors&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#e6db74">&amp;#39;replace&amp;#39;&lt;/span>))[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Так как нам доступен &lt;code>IV&lt;/code>, мы можем провести атаку bit flip на &lt;code>CBC&lt;/code>.
&lt;img src="https://uvicorn.github.io/images/luW4e8O.png" alt="">&lt;/p>
&lt;p>Суть в том, что &lt;code>P = Dec(C) ⊕ IV&lt;/code>, соответственно мы можем подменить часть &lt;code>IV&lt;/code> (в нашем случае 1 байт, потому что user_id занимает именно столько), чтобы получить желаемый плейнтекст (нам известен исходный &lt;code>P&lt;/code> , поэтому проблем не возникнет).&lt;/p>
&lt;p>Второй этап расшифрования не представляет угрозы, так как при &lt;code>CTR&lt;/code> шифротекст не используется в функции &lt;code>Dec&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://uvicorn.github.io/images/hLK3C6o.png" alt="">&lt;/p>
&lt;p>Итак, заходим в бурп, логинимся, берем куку, подменяем в ней &lt;code>IV&lt;/code> и забираем флаг.&lt;/p>
&lt;p>Вот код решения.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-python" data-lang="python">&lt;span style="color:#f92672">import&lt;/span> json
&lt;span style="color:#f92672">from&lt;/span> base64 &lt;span style="color:#f92672">import&lt;/span> b64decode, b64encode
iv_user_id_index &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>dumps({&lt;span style="color:#e6db74">&amp;#34;user_id&amp;#34;&lt;/span>:&lt;span style="color:#ae81ff">9&lt;/span>})&lt;span style="color:#f92672">.&lt;/span>index(&lt;span style="color:#e6db74">&amp;#39;9&amp;#39;&lt;/span>) &lt;span style="color:#75715e"># всегда 12&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">bit_flip&lt;/span>(cook, user_id&lt;span style="color:#f92672">=&lt;/span>&lt;span style="color:#ae81ff">0&lt;/span>):
user_id &lt;span style="color:#f92672">^=&lt;/span> &lt;span style="color:#ae81ff">1&lt;/span>
recv_json &lt;span style="color:#f92672">=&lt;/span> json&lt;span style="color:#f92672">.&lt;/span>loads(b64decode(cook)&lt;span style="color:#f92672">.&lt;/span>decode())
iv &lt;span style="color:#f92672">=&lt;/span> recv_json[&lt;span style="color:#e6db74">&amp;#39;iv&amp;#39;&lt;/span>]
iv &lt;span style="color:#f92672">=&lt;/span> list(b64decode(iv))
iv[iv_user_id_index] &lt;span style="color:#f92672">^=&lt;/span> user_id
recv_json[&lt;span style="color:#e6db74">&amp;#39;iv&amp;#39;&lt;/span>] &lt;span style="color:#f92672">=&lt;/span> b64encode(bytes(iv))&lt;span style="color:#f92672">.&lt;/span>decode()
&lt;span style="color:#66d9ef">return&lt;/span> b64encode(json&lt;span style="color:#f92672">.&lt;/span>dumps(recv_json)&lt;span style="color:#f92672">.&lt;/span>encode())
cook &lt;span style="color:#f92672">=&lt;/span> input()
user_id &lt;span style="color:#f92672">=&lt;/span> int(input())
print(bit_flip(cook, user_id)&lt;span style="color:#f92672">.&lt;/span>decode())
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Опа флаг
&lt;img src="https://uvicorn.github.io/images/7TtzCN9.png" alt="">&lt;/p>
&lt;blockquote>
&lt;p>Я до конца думал, что это unintended решение (иначе зачем класть таск на крипту вместе с тасками на веб), но содержимое флага развеяло сомнения&lt;/p>
&lt;/blockquote>
&lt;h2 id="эпилог">Эпилог&lt;/h2>
&lt;p>Мой первый райтап, мог написать дичь, не стесняйтесь критиковать.&lt;/p>
- https://uvicorn.github.io/posts/sad-rendel-writeup/ -</description></item></channel></rss>