-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathpico.html
More file actions
234 lines (222 loc) · 12.7 KB
/
pico.html
File metadata and controls
234 lines (222 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
<!DOCTYPE html>
<html>
<head>
<link rel="canonical" href="https://hardmath123.github.io/pico.html"/>
<link rel="stylesheet" type="text/css" href="/static/base.css"/>
<title>Some PicoCTF Writeups - Comfortably Numbered</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="alternate" type="application/rss+xml" title="Comfortably Numbered" href="/feed.xml" />
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$']]}
});
</script>
-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css" integrity="sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.js" integrity="sha384-YNHdsYkH6gMx9y3mRkmcJ2mFUjTd0qNQQvY9VYZgQd7DcN7env35GzlmFaZ23JGp" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/contrib/auto-render.min.js" integrity="sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// customised options
// • auto-render specific keys, e.g.:
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\begin{align}', right: '\\end{align}', display: true},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
// • rendering keys, e.g.:
throwOnError : false
});
});
</script>
</head>
<body>
<header id="header">
<script src="static/main.js"></script>
<div>
<a href="/"><span class="left-word">Comfortably</span> <span class="right-word">Numbered</span></a>
</div>
</header>
<article id="postcontent" class="centered">
<section>
<h1>Some PicoCTF Writeups</h1>
<center><em><p>In honor of PicoCTF, I wrote this post in pico.</p>
</em></center>
<h4>Saturday, November 8, 2014 · 5 min read</h4>
<p>Almost any metric of work I’ve done—homework submitted, emails answered, hours
spent playing piano, number of Github commits—show a sharp drop in the past
two weeks. I pretty much spent every moment on a computer solving
<a href="http://picoctf.com">PicoCTF</a> problems.</p>
<p>Pico was wonderful. It was an opportunity to do stuff I couldn’t (legally) do
before, and learn stuff that many adults would hesitate to teach teenagers. I
also got to hang out with cool hackers on their IRC channel, and had an excuse
to stay up till 2am hacking.</p>
<p>I’m planning on putting up some quick writeups of the problems I loved. If you
haven’t spent an hour or so with these problems, you won’t have any clue what
I’m talking about (and chances are that I myself won’t grok any of this a year
from now). Nevertheless, here goes.</p>
<h3 id="obo">OBO</h3>
<p>This problem caused too many people too many hours of pain.</p>
<p>The basic idea is that the programmer used <code><=</code> instead of <code><</code> wherever he was
iterating, so he has lots of off-by-one errors. In particular, when populating
his hex table, he has:</p>
<pre><code class="lang-c">for (i = 0; i <= 6; ++i) {
hex_table['a' + i] = 10 + i;
}
</code></pre>
<p>This allows <code>g</code> to be a valid hex character. Yay.</p>
<p>Now he goes around checking whether or not all the password characters are hex,
and he tries to make sure that all hex chars are used at least once by
populating the array <code>digits</code>. But we can input <code>g</code> in the password, so we can
set <code>digits[16]</code> which overflows into <code>password</code>:</p>
<pre><code class="lang-c">int digits[16] = {0};
char password[64];
</code></pre>
<p>So far, so good. A <code>char</code> is one byte, and an <code>int</code> (on this setup) is 4 bytes.
So when we overflow an <code>int</code> onto <code>password</code>, we set the first four characters
of the array to <code>\x01\x00\x00\x00</code> (the bytes are reversed because
Endianness!). With that zero byte, we’ve effectively reset <code>password</code> to
<code>\x01</code>. So now we can input <code>\x01</code> as the confirmation and cheat the password
changer. Yay again.</p>
<p>Now what? It uses <code>system()</code> to call a Python script. Yuck. On the bright side,
it uses a relative file path for the Python file (the author probably didn’t
test it in another working directory). So we simply <code>cd</code> into our home
directory and make a new Python script with the same name, with contents:</p>
<pre><code class="lang-python">print open('/home/obo/flag.txt').read()
</code></pre>
<p>When we send OBO the overflowed password, it runs this with the right privs and we win.</p>
<h3 id="make-a-face">Make a Face</h3>
<p>This was my favorite challenge (I have a thing for web exploitation). My first
reaction was “CGI! Shell! This must be Shellshock!” Turns out they’ve patched
their Bash, though, so that didn’t work.</p>
<p>The legitimate solution relies on the fact that Perl’s <code>open()</code> is unsafe: you
can call it with a <code>|</code> at the end, and it <em>evaluates the argument in a shell</em>,
sending back the result.</p>
<p>The webpage essentially asks the server to open the file <code>{body part
type}{index}</code>, where <code>body part type</code> is one of <code>head</code>, <code>nose</code>, etc. and
<code>index</code> looks like <code>1.bmp</code>. So, of course, we can cheat by sending it <code>1.bmp;
ls|</code> and instead of a bitmap file, the server gets a directory listing.</p>
<p>This is pretty easy to try out with <code>curl</code>…but we get back gibberish. It
looks like there’s some bitwise melding going on on the server that combines
the images. This dies when it gets <code>ls</code> output. So we just send <em>all</em> the body
part parameters the same bad index. It bitwise <code>&</code>s them together (i.e. nothing
happens) and we get the secret. Simple but beautiful.</p>
<h3 id="steve-s-list">Steve’s List</h3>
<p>This was my other favorite challenge, because there were so many different
things you needed to simultaneously break to get shell. Also, I just love the
way they used CSS3 polyfills to make the <code>blink</code> tag work in non-ancient
browsers.</p>
<p>First, there’s the cookie signing. Steve, in all his wisdom, is authenticating
cookies by maintaining a SHA1 signature of the cookie plus some secret nonce.
Turns out, this is pretty insecure because of a simple padding
message-extension hack. A quick Google search sends us <a href="http://journal.batard.info/post/2011/03/04/exploiting-sha-1-signed-messages">this blog
post</a>,
and they post some sample Python that gets the job done.</p>
<p>Though I recommend reading the blog post to actually understand what’s going
on, the basic idea is that a SHA1 hash operates on an arbitrary number of
blocks. The state of the algorithm at the end of one block is the input to the
next block’s hash (the input to the first block’s hash is a well-known
constant).</p>
<p>You don’t need to know the contents of the previous block to add another block.
So we manually pad the payload we have (that is, the cookie) and tack on our
own block. We can initialize the SHA state with the (known) hash of the first
block and then compute valid subsequent hashes without ever knowing the key.
Some quick modifications to the Python script given above let us forge
arbitrarily long messages.</p>
<p>And now for something completely different. The server reads each line of the
cookie, and unpacks it using PHP’s <code>unserialize</code>:</p>
<pre><code class="lang-php">$settings_array = explode("\n", $custom_settings);
$custom_settings = array();
for ($i = 0; $i < count($settings_array); $i++) {
$setting = $settings_array[$i];
$setting = unserialize($setting);
$custom_settings[] = $setting;
}
</code></pre>
<p>With forged objects, we can make it instantiate arbitrary objects at
will—PHP’s serialization saves type information. Notice that the <code>Post</code> object
defines:</p>
<pre><code class="lang-php">function __destruct() {
// debugging stuff
$s = "<!-- POST " . htmlspecialchars($this->title);
$text = htmlspecialchars($this->text);
foreach ($this->filters as $filter)
$text = $filter->filter($text);
$s = $s . ": " . $text;
$s = $s . " -->";
echo $s;
}
</code></pre>
<p>So it will dump its contents in an HTML comment for debugging when it’s
destroyed by the GC. Since we can instantiate arbitrary <code>Post</code> objects, we can
get their contents printed out at will. We’re very close now.</p>
<p>We can also create <code>Filter</code>s that act on the <code>Post</code>s. <code>Filter</code>s use PHP’s
<code>preg_replace</code>. That’s insecure, because you can use the <code>e</code> flag to <em>evaluate
arbitrary code</em> based on the replacement text generated from regex captures.
Argh.</p>
<p>At this point, it was around 2am, my hands felt like rubber, and my eyes felt
like mozzerella balls. So I just copied <code>posts/steve.txt</code>, and modified one of
the filters to dump the contents of the flag, and went to sleep in peace.</p>
<p>There are several lessons to be learned here, but the most important are:</p>
<ol>
<li>Don’t roll your own crypto.</li>
<li>If you do, don’t use PHP.</li>
<li>If you do, read the docs.</li>
</ol>
<h3 id="block">Block</h3>
<p>Block uses a Substitution Permutation Network to encrypt the string—but it
does it twice. I pretty much brute-forced this one. But I did it tastefully, so
it merits a writeuplet.</p>
<p>We know that the message begins with <code>message:<space></code>, and we know the first 9
bytes of the output. This lets us mount a known-plaintext attack. Here’s how:
we encrypt the plaintext with <em>all</em> possible keys (there are
$2^{24}=16777216$ of them) and we <em>decrypt</em> the ciphertext with all possible
keys. Turns out that for the correct pair of keys, we’ll get the exact same
result (the intermediate encryption). This is a ‘meet-in-the-middle’ attack
(not to be confused with ‘man-in-the-middle’ or ‘Malcolm-in-the-Middle’), and
can be read about <a href="http://en.wikipedia.org/wiki/Meet-in-the-middle_attack">on
Wikipedia</a>. This is
good—now all we need to do is find the intersection of two massive lists.</p>
<p>Once I’d compiled these lists manually (it took over an hour), I realized that
I would be graduating high school by the time a naive Python intersection
search finished. Fortunately, Python’s <code>set</code> type has ridiculously fast
member-checking, so it took all of 5 minutes to find the keypair, and I was
done.</p>
<hr>
<p>That’s all for now. I’ll probably write a couple more, depending on the amount
of homework I need to make up this week…</p>
</section>
<div id="comment-breaker">◊ ◊ ◊</div>
</article>
<footer id="footer">
<div>
<ul>
<li><a href="https://github.com/kach">
Github</a></li>
<li><a href="feed.xml">
Subscribe (RSS feed)</a></li>
<li><a href="https://twitter.com/hardmath123">
Twitter</a></li>
<li><a href="https://creativecommons.org/licenses/by-nc/3.0/deed.en_US">
CC BY-NC 3.0</a></li>
</ul>
</div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-46120535-1', 'hardmath123.github.io');
ga('require', 'displayfeatures');
ga('send', 'pageview');
</script>
</footer>
</body>
</html>