aboutsummaryrefslogtreecommitdiffstats
path: root/audit
diff options
context:
space:
mode:
Diffstat (limited to 'audit')
-rw-r--r--audit/ExMachina Code Audit | Somewhere Between Nowhere.html462
1 files changed, 462 insertions, 0 deletions
diff --git a/audit/ExMachina Code Audit | Somewhere Between Nowhere.html b/audit/ExMachina Code Audit | Somewhere Between Nowhere.html
new file mode 100644
index 0000000..f1998fe
--- /dev/null
+++ b/audit/ExMachina Code Audit | Somewhere Between Nowhere.html
@@ -0,0 +1,462 @@
+<!DOCTYPE html>
+<!--[if IE 6]>
+<html id="ie6" dir="ltr" lang="en-US">
+<![endif]-->
+<!--[if IE 7]>
+<html id="ie7" dir="ltr" lang="en-US">
+<![endif]-->
+<!--[if IE 8]>
+<html id="ie8" dir="ltr" lang="en-US">
+<![endif]-->
+<!--[if !(IE 6) | !(IE 7) | !(IE 8) ]><!-->
+<html dir="ltr" lang="en-US"><!--<![endif]--><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width">
+<title>ExMachina Code Audit | Somewhere Between Nowhere</title>
+<link rel="profile" href="http://gmpg.org/xfn/11">
+<link rel="stylesheet" type="text/css" media="all" href="ExMachina%20Code%20Audit%20%7C%20Somewhere%20Between%20Nowhere_files/style.css">
+<link rel="pingback" href="https://www.betweennowhere.net/blog/xmlrpc.php">
+<!--[if lt IE 9]>
+<script src="https://www.betweennowhere.net/blog/wp-content/themes/twentyeleven/js/html5.js" type="text/javascript"></script>
+<![endif]-->
+<meta name="robots" content="noindex,nofollow">
+<link rel="alternate" type="application/rss+xml" title="Somewhere Between Nowhere » Feed" href="https://www.betweennowhere.net/blog/feed/">
+<link rel="alternate" type="application/rss+xml" title="Somewhere Between Nowhere » Comments Feed" href="https://www.betweennowhere.net/blog/comments/feed/">
+<link rel="alternate" type="application/rss+xml" title="Somewhere Between Nowhere » ExMachina Code Audit Comments Feed" href="https://www.betweennowhere.net/blog/2012/11/exmachina/feed/">
+<script type="text/javascript" src="ExMachina%20Code%20Audit%20%7C%20Somewhere%20Between%20Nowhere_files/comment-reply.js"></script>
+<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://www.betweennowhere.net/blog/xmlrpc.php?rsd">
+<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://www.betweennowhere.net/blog/wp-includes/wlwmanifest.xml">
+<link rel="prev" title="ExMachina Review Delayed" href="https://www.betweennowhere.net/blog/2012/10/exmachina-review-delayed/">
+<link rel="next" title="I Don’t Care About the Election" href="https://www.betweennowhere.net/blog/2012/11/i-dont-care-about-the-election/">
+<meta name="generator" content="WordPress 3.4.2">
+<link rel="canonical" href="https://www.betweennowhere.net/blog/2012/11/exmachina/">
+<link rel="shortlink" href="https://www.betweennowhere.net/blog/?p=392">
+</head>
+
+<body class="single single-post postid-392 single-format-standard single-author singular two-column right-sidebar">
+<div id="page" class="hfeed">
+ <header id="branding" role="banner">
+ <hgroup>
+ <h1 id="site-title"><span><a href="https://www.betweennowhere.net/blog/" title="Somewhere Between Nowhere" rel="home">Somewhere Between Nowhere</a></span></h1>
+ <h2 id="site-description">It's a funny place to be.</h2>
+ </hgroup>
+
+ <a href="https://www.betweennowhere.net/blog/">
+ <img src="ExMachina%20Code%20Audit%20%7C%20Somewhere%20Between%20Nowhere_files/shore.jpg" alt="" height="288" width="1000">
+ </a>
+
+ <form method="get" id="searchform" action="https://www.betweennowhere.net/blog/">
+ <label for="s" class="assistive-text">Search</label>
+ <input class="field" name="s" id="s" placeholder="Search" type="text">
+ <input class="submit" name="submit" id="searchsubmit" value="Search" type="submit">
+ </form>
+
+ <nav id="access" role="navigation">
+ <h3 class="assistive-text">Main menu</h3>
+ <div class="skip-link"><a class="assistive-text" href="#content" title="Skip to primary content">Skip to primary content</a></div>
+ <div class="skip-link"><a class="assistive-text" href="#secondary" title="Skip to secondary content">Skip to secondary content</a></div>
+ <div class="menu"><ul><li><a href="https://www.betweennowhere.net/blog/" title="Home">Home</a></li></ul></div>
+ </nav><!-- #access -->
+ </header><!-- #branding -->
+
+
+ <div id="main">
+
+ <div id="primary">
+ <div id="content" role="main">
+
+
+ <nav id="nav-single">
+ <h3 class="assistive-text">Post navigation</h3>
+ <span class="nav-previous"><a href="https://www.betweennowhere.net/blog/2012/10/exmachina-review-delayed/" rel="prev"><span class="meta-nav">←</span> Previous</a></span>
+ <span class="nav-next"><a href="https://www.betweennowhere.net/blog/2012/11/i-dont-care-about-the-election/" rel="next">Next <span class="meta-nav">→</span></a></span>
+ </nav><!-- #nav-single -->
+
+
+<article id="post-392" class="post-392 post type-post status-publish format-standard hentry category-uncategorized">
+ <header class="entry-header">
+ <h1 class="entry-title">ExMachina Code Audit</h1>
+
+ <div class="entry-meta">
+ <span class="sep">Posted on </span><a href="https://www.betweennowhere.net/blog/2012/11/exmachina/" title="2131" rel="bookmark"><time class="entry-date" datetime="2012-11-04T21:31:56+00:00" pubdate="">2012.1104</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="https://www.betweennowhere.net/blog/author/nick/" title="View all posts by nick" rel="author">nick</a></span></span> </div><!-- .entry-meta -->
+ </header><!-- .entry-header -->
+
+ <div class="entry-content">
+ <ul>
+<li><a href="#exmachina-sec-1">Introduction</a></li>
+<li><a href="#exmachina-sec-2">Code Snippets</a>
+<ul>
+<li><a href="#sec2_1">Authentication</a>
+<ul>
+<li><a href="#sec2_1_1">Authentication is Optional</a>
+<ul>
+<li><a href="#exmachina-sec-2_1_1_1">Non-Optional Authentication</a></li>
+</ul>
+</li>
+<li><a href="#exmachina-sec-2_1_2">Authentication Failures Kill the Server</a></li>
+<li><a href="#exmachina-sec-2_1_3">Plain Text Passwords</a>
+<ul>
+<li><a href="#exmachina-sec-2_1_3_1">Don’t Store the Password in Plain Text</a></li>
+</ul>
+</li>
+<li><a href="#exmachina-sec-2_1_4">Untrusted Client Password Setting</a>
+<ul>
+<li><a href="#exmachina-sec-2_1_4_1">Don’t Set the Password from an Untrusted Client</a></li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="#exmachina-sec-2_2">Socket Binding</a>
+<ul>
+<li><a href="#exmachina-sec-2_2_1">A Self DOSing Platform</a>
+<ul>
+<li><a href="#exmachina-sec-2_2_1_1">Don’t Self DOS</a></li>
+</ul>
+</li>
+<li><a href="#exmachina-sec-2_2_2">Problematically Trustworthy</a>
+<ul>
+<li><a href="#exmachina-sec-2-2-2_1">Be Less Trusting</a></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</li>
+<li><a href="#exmachina-sec-3">Conclusion</a></li>
+</ul>
+<div id="outline-container-1" class="outline-2">
+<h1 id="exmachina-sec-1">Introduction</h1>
+<div id="text-1" class="outline-text-2">
+<p>I’ve been poking around <a href="https://github.com/bnewbold/exmachina">Ex Machina</a>
+ (EM) for a bit. While doing my poking, I tried to see if I could find
+any ways to break it. I’m writing this as a running log of my
+investigation, so that other folks can see bits of the investigative
+process I followed to complete a layman’s security audit.</p>
+<p>I’ll make the relevant changes to ExMachina soon. Till then, it shouldn’t be used in production.</p>
+</div>
+</div>
+<div id="outline-container-2" class="outline-2">
+<h1 id="exmachina-sec-2">Code Snippets</h1>
+<p>For each of these snippets, I’ll first display the code involved,
+then state the problems it contains, and finally post the solutions I’ve
+ been able to find for those problems.</p>
+<div id="outline-container-2_1" class="outline-3">
+<h2 id="exmachina-sec-2_1">Authentication</h2>
+<div id="text-2_1" class="outline-text-3">
+<p>For reference, I’m talking about the following block of code. Don’t
+worry if you don’t understand it, I’ll break it down the best that I can
+ understand:</p>
+<pre class="src src-python"><span style="color: #00ffff;">class</span> <span style="color: #98fb98;">ExMachinaHandler</span>(bjsonrpc.handlers.BaseHandler):
+
+ <span style="color: #ff7f24;"># authentication state variable. If not None, still need to authenticate;</span>
+ <span style="color: #ff7f24;"># if None then authentication not require or was already successful for</span>
+ <span style="color: #ff7f24;"># this instantiation of the Handler. This class variable gets optionally</span>
+ <span style="color: #ff7f24;"># overridden on a per-process basis</span>
+ secret_key = <span style="color: #7fffd4;">None</span>
+
+ <span style="color: #ff7f24;"># ... </span>
+ <span style="color: #00ffff;">def</span> <span style="color: #87cefa;">authenticate</span>(<span style="color: #00ffff;">self</span>, secret_key):
+ <span style="color: #00ffff;">if</span> <span style="color: #00ffff;">not</span> <span style="color: #00ffff;">self</span>.secret_key:
+ log.warn(<span style="color: #ffa07a;">"Unecessary authentication attempt"</span>)
+ <span style="color: #00ffff;">return</span>
+ <span style="color: #00ffff;">if</span> <span style="color: #00ffff;">not</span> <span style="color: #00ffff;">self</span>.hash(secret_key.strip()) == <span style="color: #00ffff;">self</span>.secret_key:
+ <span style="color: #ff7f24;"># fail hard </span>
+ log.error(<span style="color: #ffa07a;">"Authentication failed!"</span>)
+ sys.exit()
+ <span style="color: #00ffff;">self</span>.secret_key = <span style="color: #7fffd4;">None</span></pre>
+<p>This is a small piece of code from the class that defines an RPC
+server, the bit of code that acts on system maintenence requests from
+other programs. This is the workhorse program that actually tries to
+change the underlying system based on requests it receives. Some program
+ uses the exmachina client to send a request to the exmachina server
+which in turn changes the underlying system. If you’re a visual learner,
+ it looks like this:</p>
+<pre class="example">"some program" -&gt; "exmachina client" -&gt; "exmachina server" -&gt; "system"</pre>
+<p>Since any old “some program” could send data to the EM client, which
+passes it along to the EM server, that server had better make sure that
+only clients it trusts can send data, otherwise anybody could try to
+send destructive commands, like <code>sudo rm -rf /</code>, which is the
+ equivalent of detonating a small bomb on your computer’s harddrive:
+after that command finishes, everything you care about on your system
+will be gone.</p>
+<p>To use the authentication feature, the client does the following:</p>
+<pre class="src src-python"><span style="color: #00ffff;">class</span> <span style="color: #98fb98;">ExMachinaClient</span>():
+ <span style="color: #00ffff;">def</span> <span style="color: #87cefa;">__init__</span>(<span style="color: #00ffff;">self</span>, socket_path=<span style="color: #ffa07a;">"/tmp/exmachina.sock"</span>, secret_key=<span style="color: #7fffd4;">None</span>):
+ <span style="color: #ff7f24;"># ... some initialization ... </span>
+ <span style="color: #00ffff;">if</span> secret_key:
+ <span style="color: #00ffff;">self</span>.conn.call.authenticate(secret_key)
+ <span style="color: #ff7f24;"># ... more initialization ... </span></pre>
+<p>These code snippets create a few different problems.</p>
+</div>
+<div id="outline-container-2_1_1" class="outline-4">
+<h3 id="exmachina-sec-2_1_1">Authentication is Optional</h3>
+<div id="text-2_1_1" class="outline-text-4">
+<p>The client has to willingly use the authentication feature. Nothing
+bad happens to a client that doesn’t authenticate. The reference code
+doesn’t even handle an error condition (“if authentication fails, then
+…”), it just keeps initializing.</p>
+<p>Servers with keys don’t require clients to have or use those keys:</p>
+<pre class="src src-sh"><strong>$ echo <span style="color: #ffa07a;">"12345"</span> | ./exmachina.py -vks /tmp/exmachina.sock &amp;</strong>
+
+2012-10-20 15:06:09,562 DEBUG Waiting for secret key on stdin...
+2012-10-20 15:06:09,562 DEBUG Got it!
+2012-10-20 15:06:09,562 WARNING Expected to be running as root!
+
+<strong>$ ./test_exmachina.py</strong>
+
+========= Testing JSON-RPC connection
+/*: None
+/augeas/*: None
+/etc/* files:
+...</pre>
+<p>It should’ve bailed instead of returning results.</p>
+</div>
+<div id="outline-container-2_1_1_1" class="outline-5">
+<h4 id="exmachina-sec-2_1_1_1">Non-Optional Authentication</h4>
+<div id="text-2_1_1_1" class="outline-text-5">
+<p>The EM server should verify the client once per connection, or every
+call, if it’s impossible to determine (or possible to fake) a call’s
+source. This brings up the whole ordeal of authentication tokens, which
+is a hairy mess I’m not looking forward to.</p>
+<p>The best I can do, I think, is to just decorate every function call with an authenticator. I’m not sure how to best do this.</p>
+</div>
+</div>
+</div>
+<div id="outline-container-2_1_2" class="outline-4">
+<h3 id="exmachina-sec-2_1_2">Authentication Failures Kill the Server</h3>
+<div id="text-2_1_2" class="outline-text-4">
+<p>Incorrectly authenticating the client kills the server. This is like
+taking Google offline because somebody mistyped their Gmail passsword.</p>
+<pre class="src src-sh"><strong>$ echo <span style="color: #ffa07a;">"12345"</span> | ./exmachina.py -vks /tmp/exmachina.sock &amp;</strong>
+
+2012-10-20 15:06:09,562 DEBUG Waiting for secret key on stdin...
+2012-10-20 15:06:09,562 DEBUG Got it!
+2012-10-20 15:06:09,562 WARNING Expected to be running as root!
+
+<strong>$ echo <span style="color: #ffa07a;">"the kind of thing an idiot would have on his luggage"</span> | ./test_exmachina.py -k &amp;</strong>
+
+========= Testing JSON-RPC connection
+2012-10-20 15:05:50,453 ERROR Authentication failed!
+
+<strong>$ jobs</strong>
+
+[1]- Done echo <span style="color: #ffa07a;">"12345"</span> | ./exmachina.py -vks /tmp/exmachina.sock
+[2]+ Exit 1 echo <span style="color: #ffa07a;">"the kind of thing an idiot would have on his luggage"</span> | ./test_exmachina.py -k
+
+<strong>$</strong></pre>
+<p>The server should’ve rejected the client, the server shouldn’t've died.</p>
+<p>Looking through the code, it seems like the author might’ve forgot
+they were working in the server and actually meant to put that code in
+the client.</p>
+</div>
+</div>
+<div id="outline-container-2_1_3" class="outline-4">
+<h3 id="exmachina-sec-2_1_3">Plain Text Passwords</h3>
+<div id="text-2_1_3" class="outline-text-4">
+<p>Next, the password’s stored in plain text. An attacker who wanted to
+read the password from the server should be able to… Well, no, the
+process separation (via the socket) should prevent that, sort of. As
+long as the process separation only exposes entry points into the
+server’s functions and not the server object itself, the server’s data
+should be protected. This comes with one very obvious caveat:</p>
+<p>Anything exported by the host object can be called by the client
+object, so the client might be able to set the secret key. We should
+make sure that the secret key can only be set by a trusted user.</p>
+</div>
+<div id="outline-container-2_1_3_1" class="outline-5">
+<h4 id="exmachina-sec-2_1_3_1">Don’t Store the Password in Plain Text</h4>
+<div id="text-2_1_3_1" class="outline-text-5">
+<p>Hashing in Python is simple:</p>
+<pre class="src src-python"><span style="color: #00ffff;">def</span> <span style="color: #87cefa;">hash</span>(<span style="color: #00ffff;">self</span>, secret_key, salt):
+ <span style="color: #ffa07a;">"""Hash the secret key with the salt."""</span>
+
+ <span style="color: #00ffff;">if</span> <span style="color: #00ffff;">not</span> salt:
+ salt = os.urandom(128)
+ <span style="color: #00ffff;">return</span> hashlib.sha256(secret_key.strip() + salt)</pre>
+<p>Set the secret key to that value and it’s generally available.
+Salting with a 128 bit salt, while not strictly necessary if no client
+has access to the secret key, is nonetheless preventative, in case
+somebody does figure out how to read the key. This way, each ExMachina
+appears to have a different password (even those with the same password)
+ and those beautiful SHA256 rainbow tables are mostly irrelevant: nobody
+ creates 340282366920938463463374607431768211456 tables just in case.</p>
+</div>
+</div>
+</div>
+<div id="outline-container-2_1_4" class="outline-4">
+<h3 id="exmachina-sec-2_1_4">Untrusted Client Password Setting</h3>
+<div id="text-2_1_4" class="outline-text-4">
+<p>Unless bjsonrpc offers sufficient process separation between the server and client, <strong>this is introspective Python</strong>
+ so any program could simply reach far enough up into the client to find
+ the server and its password. Thus, even if the authentication code
+worked, the idea is still completely screwed at a fundamental level.</p>
+</div>
+<div id="outline-container-2_1_4_1" class="outline-5">
+<h4 id="exmachina-sec-2_1_4_1">Don’t Set the Password from an Untrusted Client</h4>
+<div id="text-2_1_4_1" class="outline-text-5">
+<p>So, this isn’t actually a problem, just something I wanted to point out. The process separation<strong> seems</strong> sufficient, given how bjsonrpc is built, that no client <strong>should</strong>
+ be able to reach into the server to pull out the password. The server
+exposes functions that the client can call, as filtered by bjsonrpc. If
+the server doesn’t expose it as a function, the client can’t ask for it.
+ Thus, the client can’t simply ask for non-functional data: that’s
+effectively private, thanks to the process separation.</p>
+<p>Even if clients could read the hashed password, as long as they can’t
+ set data directly on the server, we can safely allow clients to set a
+custom password. First, we’d need to force the server to reject any
+subsequent attempts to set the password, if it’s already set, and then
+we’d need to prevent untrusted users from writing to the socket until
+the password is successfully set. We can prevent users from writing data
+ to the socket by setting the file permissions on the socket correctly
+(0×0600, preventing other users from writing to it), before we start
+using it for communication. Preventing the server from accepting a new
+password involves adding only a few lines of code:</p>
+<pre class="src src-python"><span style="color: #00ffff;">def</span> <span style="color: #87cefa;">set_password</span>(<span style="color: #00ffff;">self</span>, password):
+ <span style="color: #00ffff;">if</span> <span style="color: #00ffff;">self</span>.secret_key:
+ <span style="color: #00ffff;">return</span>
+ <span style="color: #00ffff;">else</span>:
+ <span style="color: #00ffff;">self</span>.secret_key = <span style="color: #00ffff;">self</span>.hash(password, <span style="color: #00ffff;">self</span>.salt)</pre>
+<p>Even if client functions can be re-bound, the server’s process separation still protects us here. So, a client could change<code> self.server.call.set_password</code>
+ to another function, but then it’s no longer a parameter-passing shim
+between the client and server process (the part that does the real
+work): the client can change its functions, but then it’s no longer
+calling the server. This is just message passing, so as long as bjsonrpc
+ itself doesn’t support clients modifying the server (which I didn’t see
+ evidence of when I looked, but might’ve missed, but would be shameful
+if it did exist).</p>
+</div>
+</div>
+</div>
+</div>
+<div id="outline-container-2_2" class="outline-3">
+<h2 id="exmachina-sec-2_2">Socket Binding</h2>
+<div id="text-2_2" class="outline-text-3">
+<p>This might be the most important problem, but is likely the one that
+requires the most code changes and strictest set of fixes. See if you
+can’t figure out what’s up with this code:</p>
+<pre class="src src-python"><span style="color: #00ffff;">def</span> <span style="color: #87cefa;">run_server</span>(socket_path, secret_key=<span style="color: #7fffd4;">None</span>, socket_group=<span style="color: #7fffd4;">None</span>):
+ <span style="color: #ff7f24;"># ... </span>
+ <span style="color: #00ffff;">if</span> os.path.exists(socket_path):
+ os.unlink(socket_path)
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.bind(socket_path)
+ sock.listen(1)
+
+ <span style="color: #00ffff;">if</span> socket_group <span style="color: #00ffff;">is</span> <span style="color: #00ffff;">not</span> <span style="color: #7fffd4;">None</span>:
+ socket_uid = os.stat(socket_path).st_uid
+ socket_gid = grp.getgrnam(socket_group).gr_gid
+ os.chmod(socket_path, 0660)
+ os.chown(socket_path, socket_uid, socket_gid)
+ <span style="color: #00ffff;">else</span>:
+ os.chmod(socket_path, 0666)
+ <span style="color: #ff7f24;"># ... </span></pre>
+</div>
+<div id="outline-container-2_2_1" class="outline-4">
+<p id="exmachina-sec-2_2_1">There are two problems.&nbsp; Did you catch them both?</p>
+<h3>A Self DOSing Platform</h3>
+<div id="text-2_2_1" class="outline-text-4">
+<p>If you create multiple ExMachinae each one takes over the default socket after it initializes, DOSing the real EM.</p>
+</div>
+<div id="outline-container-2_2_1_1" class="outline-5">
+<h4 id="exmachina-sec-2_2_1_1">Don’t Self DOS</h4>
+<div id="text-2_2_1_1" class="outline-text-5">
+<p>Unix file permissions to the rescue again! Set the <strong>directory that contains the socket files</strong> to forbid writes from any but the owning user. That’ll prevent anyone <em>else</em> from overwriting the existing sockets.</p>
+<p>If we do that, each socket that replaces the previous one will have
+the same permissions the previous one did. We’ll lose communication with
+ running processes, but that’s about it.</p>
+</div>
+</div>
+</div>
+<div id="outline-container-2_2_2" class="outline-4">
+<h3 id="exmachina-sec-2_2_2">Problematically Trustworthy</h3>
+<div id="text-2_2_2" class="outline-text-4">
+<p>We accept input from any user on the system. As mentioned above,
+that’s not a great idea, because it makes the process vulnerable to a
+wider selection of attackers than necessary.</p>
+</div>
+<div id="outline-container-2_2_2_1" class="outline-5">
+<h4 id="exmachina-sec-2_2_2_1">Be Less Trusting</h4>
+<div id="text-2_2_2_1" class="outline-text-5">
+<p>Simple. Don’t give any groups access to the socket unless specifically requested. <strong>Never</strong> give the <em>other</em> user access to the socket.</p>
+<pre class="src src-python"><span style="color: #00ffff;">def</span> <span style="color: #87cefa;">run_server</span>(socket_path, secret_key=<span style="color: #7fffd4;">None</span>, socket_group=<span style="color: #7fffd4;">None</span>):
+ <span style="color: #ff7f24;"># ... </span>
+ <span style="color: #00ffff;">if</span> os.path.exists(socket_path):
+ os.unlink(socket_path)
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.bind(socket_path)
+
+ os.chmod(socket_path, 0600)
+
+ <span style="color: #00ffff;">if</span> socket_group:
+ os.chmod(socket_path, 0660)
+ os.chown(socket_path, gid=grp.getgrnam(socket_group).gr_gid)
+ <span style="color: #ff7f24;"># ... </span></pre>
+</div>
+</div>
+</div>
+</div>
+</div>
+<div id="outline-container-3" class="outline-2">
+<h1 id="exmachina-sec-3">Conclusion</h1>
+<div id="text-3" class="outline-text-2">
+<p>ExMachina is a neat idea but it shouldn’t be used till these issues
+are fixed. Then, it should be considered in a testing phase, undergo
+peer review, and folks should try to break it for a while before it’s
+considered solid.</p>
+</div>
+</div>
+<div style="display: none; font-style: normal; left: 0px; top: 0px; position: absolute; z-index: 9999; border: 1px solid black; background-color: white; padding: 4px;">is a…<p></p>
+<div></div>
+</div>
+ </div><!-- .entry-content -->
+
+ <footer class="entry-meta">
+ This entry was posted in <a href="https://www.betweennowhere.net/blog/category/uncategorized/" title="View all posts in Uncategorized" rel="category tag">Uncategorized</a> by <a href="https://www.betweennowhere.net/blog/author/nick/">nick</a>. Bookmark the <a href="https://www.betweennowhere.net/blog/2012/11/exmachina/" title="Permalink to ExMachina Code Audit" rel="bookmark">permalink</a>.
+ </footer><!-- .entry-meta -->
+</article><!-- #post-392 -->
+
+ <div id="comments">
+
+
+
+ <div id="respond">
+ <h3 id="reply-title">Leave a Reply <small><a rel="nofollow" id="cancel-comment-reply-link" href="https://www.betweennowhere.net/blog/2012/11/exmachina/#respond" style="display: none;">Cancel reply</a></small></h3>
+ <form action="https://www.betweennowhere.net/blog/wp-comments-post.php" method="post" id="commentform">
+ <p class="comment-notes">Your email address will not be published. Required fields are marked <span class="required">*</span></p> <p class="comment-form-author"><label for="author">Name</label> <span class="required">*</span><input id="author" name="author" size="30" aria-required="true" type="text"></p>
+<p class="comment-form-email"><label for="email">Email</label> <span class="required">*</span><input id="email" name="email" size="30" aria-required="true" type="text"></p>
+<p class="comment-form-url"><label for="url">Website</label><input id="url" name="url" size="30" type="text"></p>
+ <p class="comment-form-comment"><label for="comment">Comment</label><textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea></p> <p class="form-allowed-tags">You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes: <code>&lt;a
+ href="" title=""&gt; &lt;abbr title=""&gt; &lt;acronym title=""&gt;
+&lt;b&gt; &lt;blockquote cite=""&gt; &lt;cite&gt; &lt;code&gt; &lt;del
+datetime=""&gt; &lt;em&gt; &lt;i&gt; &lt;q cite=""&gt; &lt;strike&gt;
+&lt;strong&gt; </code></p> <p class="form-submit">
+ <input name="submit" id="submit" value="Post Comment" type="submit">
+ <input name="comment_post_ID" value="392" id="comment_post_ID" type="hidden">
+<input name="comment_parent" id="comment_parent" value="0" type="hidden">
+ </p>
+ </form>
+ </div><!-- #respond -->
+
+</div><!-- #comments -->
+
+
+ </div><!-- #content -->
+ </div><!-- #primary -->
+
+
+ </div><!-- #main -->
+
+ <footer id="colophon" role="contentinfo">
+
+
+
+ <div id="site-generator">
+ <a href="http://wordpress.org/" title="Semantic Personal Publishing Platform" rel="generator">Proudly powered by WordPress</a>
+ </div>
+ </footer><!-- #colophon -->
+</div><!-- #page -->
+
+
+
+</body></html> \ No newline at end of file