<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://luke.abq.nm.us/feed.xml" rel="self" type="application/atom+xml" /><link href="http://luke.abq.nm.us/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-05-15T02:42:25+00:00</updated><id>http://luke.abq.nm.us/feed.xml</id><title type="html">Luke Rindels</title><subtitle>Luke Rindels - Information Security Researcher and Developer
</subtitle><author><name>Luke Rindels</name><email>lrindels+blog@pm.me</email></author><entry><title type="html">Discovering Null Byte Injection Vulnerability in GoAhead</title><link href="http://luke.abq.nm.us/blog/2021-04-26-Embedded-Webserver-Null-Byte-Injection/" rel="alternate" type="text/html" title="Discovering Null Byte Injection Vulnerability in GoAhead" /><published>2021-04-26T00:00:00+00:00</published><updated>2021-04-26T00:00:00+00:00</updated><id>http://luke.abq.nm.us/blog/Embedded-Webserver-Null-Byte-Injection</id><content type="html" xml:base="http://luke.abq.nm.us/blog/2021-04-26-Embedded-Webserver-Null-Byte-Injection/"><![CDATA[<ul id="markdown-toc">
  <li><a href="#the-casablanca-camera-caper" id="markdown-toc-the-casablanca-camera-caper">The Casablanca Camera Caper</a></li>
  <li><a href="#javascript-templates-" id="markdown-toc-javascript-templates-">Javascript Templates 😬</a></li>
  <li><a href="#extension-handling" id="markdown-toc-extension-handling">Extension Handling</a></li>
  <li><a href="#over-protective-chrome" id="markdown-toc-over-protective-chrome">Over-Protective Chrome</a></li>
  <li><a href="#aftermath" id="markdown-toc-aftermath">Aftermath</a></li>
  <li><a href="#acknowledgments" id="markdown-toc-acknowledgments">Acknowledgments</a></li>
</ul>

<p>I had the privilege of testing problems for <a href="https://plaidctf.com/">PlaidCTF</a> 2021, where I spent a decent amount of time on the Carmen Sandiego series of challenges. The basic premise is that the player can manipulate sensor and camera snapshot values that are visible to an admin on the web interface. Somehow, the admin must be tricked into divulging the flag at <code class="language-plaintext highlighter-rouge">/cgi-bin/flag</code>.</p>

<p>GoAhead is the web server for this problem and, <a href="https://www.embedthis.com/goahead/doc/index.html">according to their website</a>, is the “worlds most popular embedded web server” used in “hundreds of millions of devices”. The intended solution was to exploit a zero-day in GoAhead where the Content-Length response header would incorrectly state the amount of data in the response under certain conditions. I happened to come across a <em>different</em> zero-day that allows an attacker to choose an arbitrary extension for a file, which turns out can be very useful. For instance, it would have made solving the Carmen Sandiego problems much easier if Chrome allowed encoded null bytes in URLs.</p>

<h2 id="the-casablanca-camera-caper">The Casablanca Camera Caper</h2>

<p>In this version of the problem, the player can upload “snapshots” that are visible to the admin on the main dashboard.</p>

<p><img src="/assets/img/blog/2/snapshot.png" alt="Snapshots" /></p>

<p>The snapshot names are protected by a solid regex:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">KEY_REGEX</span> <span class="o">=</span> <span class="sa">r</span><span class="s">"([a-z]{1,512})"</span>
</code></pre></div></div>

<p>But, the contents of the snapshots have no limitations other than a generous maximum size of 1MiB. The player is also allowed to specify a URL for the admin to visit once they have logged in and seen the snapshot view. So why can’t we just upload a script that fetches and sends the script to us by having the admin visit the snapshot URL? Content Security Policy of course!</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">Content-Security-Policy: default-src 'self'; script-src 'nonce-a3bdb41f7d7b5edcf53b185662585b42'; img-src *
</span></code></pre></div></div>

<p>In English: only images are allowed to interact with external origins, all scripts must contain a unique nonce attribute that changes every time the file is served, and everything else (like iframes) must be from the origin of the challenge app.</p>

<p>The biggest obstacle here is the nonce-based script policy. It’s also interesting because GoAhead does not provide this capability by default, it was added in a patch by the challenge author. This made it the focus of my exploitation efforts.</p>

<h2 id="javascript-templates-">Javascript Templates 😬</h2>

<p>The homepage (<code class="language-plaintext highlighter-rouge">index.html</code>) requires a nonce to be able to load its script (<code class="language-plaintext highlighter-rouge">main.js</code>). So let’s see  how the web server knows to put a nonce in the right place by looking at the raw, non-served version of <code class="language-plaintext highlighter-rouge">index.html</code>:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">nonce=</span><span class="s">"&lt;% nonce(); %&gt;"</span> <span class="na">src=</span><span class="s">"main.js"</span><span class="nt">&gt;&lt;/script&gt;</span>
</code></pre></div></div>

<p>Interesting! I attempted to do a similar thing in a snapshot with an inline script:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">nonce=</span><span class="s">"&lt;% nonce(); %&gt;"</span><span class="nt">&gt;</span> <span class="nx">alert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>This didn’t work… Nothing was replaced by the web server. At this point I RTFMd and found <a href="https://www.embedthis.com/goahead/doc/users/jst.html">Javascript Templates</a>. GoAhead’s documentation explains that <code class="language-plaintext highlighter-rouge">.jst</code> files are processed by a JST handler that looks for delimiters (<code class="language-plaintext highlighter-rouge">&lt;% %&gt;</code>), executes the specified script, and then replaces the contents with the result of the script. There is one default function, <code class="language-plaintext highlighter-rouge">write()</code>. The author of this challenge add the <code class="language-plaintext highlighter-rouge">nonce()</code> function as a part of their nonce-based CSP implementation.</p>

<p>If the JST handler is meant for <code class="language-plaintext highlighter-rouge">.jst</code> files, why did it work on <code class="language-plaintext highlighter-rouge">index.html</code>? Turns out you can tell GoAhead which handlers you wannt for different extensions when specifying routes which is what the challenge author did:</p>

<div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">// file: "/etc/route.txt"
route uri=/ extensions=html handler=jst
</span></code></pre></div></div>

<p>If the snapshot names could have a period then a snapshot could have a <code class="language-plaintext highlighter-rouge">.html</code> extension to get a valid nonce!</p>

<p class="note">As an aside, Javascript templates do not seem very safe. I’m curious how they’re used in legitimate applications and whether or not those uses pose any risk.</p>

<h2 id="extension-handling">Extension Handling</h2>

<p>I tried a few things to see if I could trick GoAhead into thinking my snapshots had an HTML extension like ending the filename with <code class="language-plaintext highlighter-rouge">html</code> without the period. It was a long shot and nothing worked. But this is meant for a CTF! Maybe there was something wrong with how GoAhead parses extensions and I needed to dive into the source. So that’s what I did.</p>

<p>This is how GoAhead gets the extension from a request (<a href="https://github.com/embedthis/goahead-gpl/blob/b4576343bb956ddeac265a3ae0d72a7df1f44930/src/http.c#L2663">Source</a>):</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="c1">// file: "http.c"</span>
  <span class="cm">/* [/path] */</span>
    <span class="k">if</span> <span class="p">(</span><span class="o">*</span><span class="n">tok</span><span class="p">)</span> <span class="p">{</span>
        <span class="cm">/*
           Terminate hostname. This zeros the leading path slash.
           This will be repaired before returning if ppath is set
         */</span>
        <span class="n">sep</span> <span class="o">=</span> <span class="o">*</span><span class="n">tok</span><span class="p">;</span>
        <span class="o">*</span><span class="n">tok</span><span class="o">++</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
        <span class="n">path</span> <span class="o">=</span> <span class="n">tok</span><span class="p">;</span>
        <span class="cm">/* path[.ext[/extra]] */</span>
        <span class="k">if</span> <span class="p">((</span><span class="n">tok</span> <span class="o">=</span> <span class="n">strrchr</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="sc">'.'</span><span class="p">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">tok</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">((</span><span class="n">delim</span> <span class="o">=</span> <span class="n">strrchr</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="sc">'/'</span><span class="p">))</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                    <span class="k">if</span> <span class="p">(</span><span class="n">delim</span> <span class="o">&lt;</span> <span class="n">tok</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">ext</span> <span class="o">=</span> <span class="n">tok</span><span class="p">;</span>
                    <span class="p">}</span>
                <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                    <span class="n">ext</span> <span class="o">=</span> <span class="n">tok</span><span class="p">;</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">}</span>
    <span class="p">}</span>
</code></pre></div></div>

<p>At this point I figured the request URL must have been decoded, otherwise it wouldn’t be able to call <code class="language-plaintext highlighter-rouge">strrchr()</code> with <code class="language-plaintext highlighter-rouge">.</code> and <code class="language-plaintext highlighter-rouge">/</code> delimiters.</p>

<p>So… what if there was a null byte in the URL? Null byte injection is a <a href="https://owasp.org/www-community/attacks/Embedding_Null_Code">well-known</a> technique, but this isn’t really a place I would expect to be useful. In my mind there were a couple possibilities:</p>

<ol>
  <li>Dangerous URL encodings like <code class="language-plaintext highlighter-rouge">%00</code> aren’t allowed. An error will be served</li>
  <li>Dangerous URL encodings like <code class="language-plaintext highlighter-rouge">%00</code> aren’t decoded. A request for <code class="language-plaintext highlighter-rouge">/example%00.html</code> will attempt to serve <code class="language-plaintext highlighter-rouge">/example%00.html</code></li>
  <li>If the <code class="language-plaintext highlighter-rouge">%00</code> is decoded, in a request for <code class="language-plaintext highlighter-rouge">/example%00.html</code> the extension will simply be cut-off. There will be no extension and GoAhead will attempt to serve <code class="language-plaintext highlighter-rouge">/example</code>.</li>
</ol>

<p>Nevertheless, I uploaded a snapshot with the name <code class="language-plaintext highlighter-rouge">example</code> with the following contents:</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;script </span><span class="na">nonce=</span><span class="s">"&lt;% nonce(); %&gt;"</span><span class="nt">&gt;</span> <span class="nx">alert</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="nt">&lt;/script&gt;</span>
</code></pre></div></div>

<p>Then I made a request for <code class="language-plaintext highlighter-rouge">/data/snapshot/example%00.html</code> and to my amazement the nonce was there!</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>curl <span class="s1">'http://localhost/data/snapshot/example%00.html'</span> <span class="nt">-H</span> <span class="s1">'Cookie: -goahead-session-=::webs.session::9bf107c4ed34c7320fb37d2cb400b85f'</span>

&lt;script <span class="nv">nonce</span><span class="o">=</span><span class="s2">"7616bb8945f2eaf7f228871aed78c909"</span><span class="o">&gt;</span>alert<span class="o">(</span>1<span class="o">)</span>&lt;/script&gt;
</code></pre></div></div>

<p>Despite the challenge bot using <a href="https://developers.google.com/web/tools/puppeteer">Puppeteer</a> (a Chrome automation tool), I was testing with Firefox. I navigated to the same URL and it worked!</p>

<p><img src="/assets/img/blog/2/xss.png" alt="XSS" /></p>

<p>This meant that my assumptions were incorrect. The URL is parsed as having the <code class="language-plaintext highlighter-rouge">.html</code> extension, meaning the JST handler is invoked. But when it is time to fetch the file, the null byte comes into play and <code class="language-plaintext highlighter-rouge">example</code> is grabbed instead of <code class="language-plaintext highlighter-rouge">example%00.html</code>. We get the best of both worlds! This is also pretty serious because it manys any route that depends on an extension to determine the correct handler can be bypassed!</p>

<h2 id="over-protective-chrome">Over-Protective Chrome</h2>

<p>I was ecstatic and confidently ran my solution on the live test server hosted by the author to get the flag.</p>

<p>Nothing happened.</p>

<p>I ran it again.</p>

<p><strong>NOTHING.</strong></p>

<p>Confidence shaken, I ran it locally and received this error from Puppeteer:</p>

<div class="language-docker highlighter-rouge"><div class="highlight"><pre class="highlight"><code>victim_1  | (node:30) UnhandledPromiseRejectionWarning: Error: Protocol error (Page.navigate): Cannot navigate to invalid URL
victim_1  |     at /home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:208:63
victim_1  |     at new Promise (&lt;anonymous&gt;)
victim_1  |     at CDPSession.send (/home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/Connection.js:207:16)
victim_1  |     at navigate (/home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:108:47)
victim_1  |     at FrameManager.navigateFrame (/home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:91:13)
victim_1  |     at Frame.goto (/home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/FrameManager.js:416:41)
victim_1  |     at Page.goto (/home/bot/node_modules/puppeteer/lib/cjs/puppeteer/common/Page.js:789:53)
victim_1  |     at /home/bot/dist/index.js:34:20
victim_1  |     at Generator.next (&lt;anonymous&gt;)
victim_1  |     at fulfilled (/home/bot/dist/index.js:5:58)
victim_1  | (Use `node --trace-warnings ...` to show where the warning was created)
victim_1  | (node:30) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html<span class="c">#cli_unhandled_rejections_mode). (rejection id: 1)</span>
victim_1  | (node:30) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
</code></pre></div></div>

<p>I did some digging and confirmed that Chrome does not allow encoded null bytes in URLs. <a href="https://news.ycombinator.com/item?id=22282176">This</a> is a pretty good thread on the subject that discusses some of the differences in how URLs are parsed across different applications. Unfortunately that meant I wouldn’t be able to get the flag using this exploit :(</p>

<p>Maybe there was a way to bypass how Chrome parses URLs? That sounded extreme and I had already spent a lot of time getting to this point, so I just asked the challenge author. He let me know that I wasn’t anywhere close to the unintended solution and that I should report my findings to GoAhead.</p>

<h2 id="aftermath">Aftermath</h2>

<p>GoAhead has a dedicated email for security reporting that was easy to find. The security contact also responded very quickly with a more detailed explanation of the vulnerability than I worked out and the strategy for patching. The next day it was patched. Here is how he explained it:</p>

<blockquote class="lead">
  <p>Definitely not correct handling. We’ve prepared an update that does not decode %00 to NULL.  Our GoAhead 2 &amp; 5 versions do not have this issue as we explicitly reject %00. 
We are back porting this to version 4 which is our GPL and evaluation version.</p>

  <p>The interpretation of the route extension property is NOT for file extensions, but URL extensions. These are often the same, but not always.</p>

  <p>So the request:</p>

  <p><code class="language-plaintext highlighter-rouge">curl http://127.0.0.1/example%00.jst</code></p>

  <p>Is actually asking for the URL that ends with html, which this URL does. Not for the file that ends with “.jst”.  i.e. it is correct to invoke the JST handler as the URL has a ‘.jst’ extension.</p>

  <p>The issue is that the resolved physical file name does not match the URL of “example%00.jst”. i.e. the NULL truncates the file name and an unexpected file name is served.</p>

  <p>Our patch preserves the %00 and so the filename then matches the URL. If there is a file named “example%00.jst” literally, then it will be executed correctly.</p>

  <p>To exploit, it would need to be coupled with another exploit or weak configuration. i.e. you need to have a file uploaded which has JST which should not be executed as such.
   Using a URL as “/“ with extensions=“jst” handler=jst is okay, provided you do not allow upload to the same directory. Upload should only be allowed to a restricted directory.</p>
</blockquote>

<p>The GitHub issue can be found here: <a href="https://github.com/embedthis/goahead-gpl/issues/5">https://github.com/embedthis/goahead-gpl/issues/5</a></p>

<p>Props to GoAhead for handling this so well. As I found out when writing my <a href="/blog/2019-05-16-Bypassing-Cinemark-Gap-Restriction/">previous blog post</a> two years ago, some companies are not nearly as responsive to vulnerability reports.</p>

<p>Moving forward, I may try to see if I can get this filed as a CVE. I don’t know much about the how that works, but I think this would a good opportunity to learn.</p>

<p>Thanks for reading!</p>

<h2 id="acknowledgments">Acknowledgments</h2>
<ul>
  <li>Thanks to <a href="https://twitter.com/thebluepichu?lang=en">@thebluepichu</a> for developing this challenge and encouraging me to report my findings</li>
  <li>Thanks to <a href="https://github.com/mobsense">Michael O’Brien</a> for being a pleasant and responsive point of contact at GoAhead</li>
</ul>]]></content><author><name>Luke Rindels</name><email>lrindels+blog@pm.me</email></author><category term="blog" /><summary type="html"><![CDATA[How I found a zero-day in an embedded web server while testing problems for PlaidCTF 2021.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://luke.abq.nm.us/assets/img/blog/2/iothub.png" /><media:content medium="image" url="http://luke.abq.nm.us/assets/img/blog/2/iothub.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Bypassing Cinemark’s Gap Restriction</title><link href="http://luke.abq.nm.us/blog/2019-05-16-Bypassing-Cinemark-Gap-Restriction/" rel="alternate" type="text/html" title="Bypassing Cinemark’s Gap Restriction" /><published>2019-05-16T00:00:00+00:00</published><updated>2019-05-16T00:00:00+00:00</updated><id>http://luke.abq.nm.us/blog/Bypassing-Cinemark-Gap-Restriction</id><content type="html" xml:base="http://luke.abq.nm.us/blog/2019-05-16-Bypassing-Cinemark-Gap-Restriction/"><![CDATA[<p>Cinemark uses an online seat reservation system. Presumably to maximize the amount of seats they can sell, they no longer allow a seat gap to be left when making reservations. I discovered this when trying to make reservations for a very full showing of <em>Avengers: Endgame</em>. The website would not allow me to choose seats that would leave one seat between me and the wall or other reserved seats. No one likes sitting next to strangers, so I decided to see if this restriction was something that might have a workaround.</p>

<p><img src="/assets/img/blog/1/gap_error.png" alt="Gap Seat Error" /></p>

<p>It was time to fire up <a href="https://portswigger.net/burp">Burp</a> and see what sort of requests are being made when choosing seats. I was very surprised to see that as soon as proxy intercepting was turned on, all clicks on the seat map resulted in a request to Facebook.</p>

<p><img src="/assets/img/blog/1/facebook.png" alt="Facebook" /></p>

<p>There is a ton of interesting information included in those Facebook requests, but I needed to stay on task if I was going to get an <em>Endgame</em> seat on opening weekend without having to sit next to someone with the flu or a kid that snuck in a family size bag of potato chips. The request I cared about was the one that seemingly resulted in an error message.</p>

<p>Interestingly enough, no requests are sent to Cinemark when the <strong>Reserve Selected Seats</strong> button is pressed (still just Facebook), leading me to believe that the error is processed client side. A big mistake.</p>

<p>The next step was to see what kind of request gets sent out for a valid reservation. Clicking on a seat that does not leave a gap produces a wonderful request with an abundance of human-readable parameters.</p>

<p><img src="/assets/img/blog/1/res_request.png" alt="Reservation Request" /></p>

<p>Modifying this request could result in a nice and easy bypass of the seat gap restriction; however, it is still possible that there is some validation on the server side that prevents things like this from happening. Also, the last two numbers in the <code class="language-plaintext highlighter-rouge">SeatToHold</code> parameter are not obvious. I decided to try another seat to see if it resulted in a pattern.</p>

<p><img src="/assets/img/blog/1/seattohold.png" alt="SeatToHold Deduction" /></p>

<p>Incrementing the row number and decrementing the column number gives us a clear picture of how the seat map works. To reserve the initial desired seat of <code class="language-plaintext highlighter-rouge">F12</code>, the <code class="language-plaintext highlighter-rouge">SeatToHold</code> parameter needs to be modified to <code class="language-plaintext highlighter-rouge">F-12-6-4</code>. Cinemark also includes a lovely feature that allows anyone to temporarily reserve seats before actually making a purchase. This can be used to verify that the modified request works.</p>

<p>The first sign that the modified request works is that the resulting ticket number has been changed to <code class="language-plaintext highlighter-rouge">F12</code>.</p>

<p><img src="/assets/img/blog/1/ticket.png" alt="Modified Ticket Number" /></p>

<p>Going through the seat reservation process again also shows that <code class="language-plaintext highlighter-rouge">F12</code> is not available, even though it is still creating a single contiguous space in <code class="language-plaintext highlighter-rouge">F13</code>.</p>

<p><img src="/assets/img/blog/1/seat.png" alt="Seat Confirmation" /></p>

<p>Of course the only way to truly tell if it works is by actually purchasing the ticket and showing up, but I have a feeling *wink* that it absolutely does work. I have attempted to contact Cinemark to report this issue, but they don’t seem to have taken it too seriously and I would not be surprised if the workaround persists.</p>

<p>As you can probably imagine, this method could be used for many malicious (and less petty) purposes. Some things off the top of my head include reserving all seats as soon as tickets open up in order to prevent actual customers from buying tickets or double booking seats to cause mayhem. It’s imperative that companies have a system in place for public reporting of bugs and take the provided information seriously.</p>

<p>PS. I found out later that the first two values in the <code class="language-plaintext highlighter-rouge">SeatToHold</code> parameter describe the seat number (obviously) and are the values printed on the ticket and in the reservation. The last 2 values are the seats that are reserved in the online seat map. Only changing one pair of values results in either duplicate tickets printed out or double booking of seats.</p>]]></content><author><name>Luke Rindels</name><email>lrindels+blog@pm.me</email></author><category term="blog" /><summary type="html"><![CDATA[Cinemark doesn't want people to leave gap seats when reserving tickets, but not badly enough to implement a server-side check...]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://luke.abq.nm.us/assets/img/blog/1/seat.png" /><media:content medium="image" url="http://luke.abq.nm.us/assets/img/blog/1/seat.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>