diff options
Diffstat (limited to 'audit/ExMachina Code Audit | Somewhere Between Nowhere.html')
-rw-r--r-- | audit/ExMachina Code Audit | Somewhere Between Nowhere.html | 462 |
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" -> "exmachina client" -> "exmachina server" -> "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 &</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 &</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 &</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. 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><a + href="" title=""> <abbr title=""> <acronym title=""> +<b> <blockquote cite=""> <cite> <code> <del +datetime=""> <em> <i> <q cite=""> <strike> +<strong> </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 |