<?xml version="1.0"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jon Cave</title>
    <link>http://joncave.co.uk</link>
    <description></description>
    <atom:link href="http://joncave.co.uk/rss.xml" rel="self" type="application/rss+xml" />
    <language>en-gb</language>
    <pubDate>Mon, 15 Jan 2018 21:12:50 UTC</pubDate>
    <lastBuildDate>Mon, 15 Jan 2018 21:12:50 UTC</lastBuildDate>

    
      <item>
        <title>Exploiting Bitcoin's SIGHASH_SINGLE signature type</title>
        <link>http://joncave.co.uk/2014/08/bitcoin-sighash-single/</link>
        <pubDate>Fri, 08 Aug 2014 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2014/08/bitcoin-sighash-single/</guid>
        <description>&lt;p&gt;Coinspect, a new Bitcoin focused security company, recently disclosed technical details of an &lt;a href=&quot;http://blog.coinspect.co/copay-wallet-emptying-vulnerability&quot;&gt;attack against Copay’s multisignature wallets&lt;/a&gt;. At the same time they &lt;a href=&quot;https://twitter.com/coinspect/status/494246121796276225&quot;&gt;issued a challenge&lt;/a&gt; to recover the Bitcoins that had been used to test the Copay exploit. This post will go over the details of this challenge and how to solve it.&lt;/p&gt;

&lt;p&gt;When the challenge started there were two unspent transaction outputs associated with the target Bitcoin address. It appeared that the challenge would be to find some way to spend these outputs without knowledge of the private keys that are normally required to sign a transaction.&lt;/p&gt;

&lt;p&gt;Throughout this post I am going to make use of &lt;a href=&quot;https://github.com/vbuterin/pybitcointools&quot;&gt;pybitcointools&lt;/a&gt; to perform Bitcoin related operations from the command line.&lt;/p&gt;

&lt;h2 id=&quot;redeeming-a-bitcoin-transaction&quot;&gt;Redeeming a Bitcoin transaction&lt;/h2&gt;

&lt;p&gt;A Bitcoin transaction moves coins between one or more inputs and outputs. Each input spends the coins paid to a previous output, and each output waits as an unspent transaction output until it is spent as an input to a later transaction.&lt;/p&gt;

&lt;p&gt;An output contains the amount that has been transferred and a script that describes the conditions that must be met in order for the output to be spent. An input references an output in a previous transaction — a transaction ID (the hash of the transaction data) and output index — and provides a script, known as the scriptSig, that satifies the output script conditions.&lt;/p&gt;

&lt;p&gt;In the simplest case, a Bitcoin address is the hash of a user’s public key. In order to send some Bitcoin to this user a pay-to-public-key-hash (P2PKH) transaction output is created. The P2PKH output script contains instructions that allow the owner of the private key that corresponds to the hashed public key to spend the output. Such a script looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;OP_DUP OP_HASH160 &amp;lt;PublicKeyHash&amp;gt; OP_EQUALVERIFY OP_CHECKSIG
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The corresponding scriptSig that redeems this output is simply two pieces of data: the receivers public key, and a signature of the transaction data with the private key. (Note that the signature is of the new transaction that is spending the previous output). Not only does the signature prove ownership of the expected private key, but it also protects the new transaction against modification.&lt;/p&gt;

&lt;p&gt;In order to verify a transaction the output script is appended to the scriptSig:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;Sig&amp;gt; &amp;lt;PublicKey&amp;gt; OP_DUP OP_HASH160 &amp;lt;PublicKeyHash&amp;gt; OP_EQUALVERIFY OP_CHECKSIG
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This entire script is then evaluated. If the resulting stack has the value true at the top then the transaction is valid.&lt;/p&gt;

&lt;p&gt;In this example of the most common form of transaction the &lt;code&gt;OP_EQUALVERIFY&lt;/code&gt; and &lt;code&gt;OP_CHECKSIG&lt;/code&gt; instructions must both complete successfully. &lt;code&gt;OP_EQUALVERIFY&lt;/code&gt; will check that the public key provided in the scriptSig matches the expected hash in the output script, and &lt;code&gt;OP_CHECKSIG&lt;/code&gt; will verify the signature of the transaction against the public key. For a full run through of the script execution see the Bitcoin developer guide on &lt;a href=&quot;https://bitcoin.org/en/developer-guide#p2pkh-script-validation&quot;&gt;P2PKH Script Validation&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;p2sh-addresses&quot;&gt;P2SH Addresses&lt;/h2&gt;

&lt;p&gt;With a basic understanding of Bitcoin transactions it is now time to take a look at the two unspent transactions associated with the target wallet:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; target = &#39;32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe&#39;
&amp;gt;&amp;gt;&amp;gt; unspent(target)
[{&#39;output&#39;: &#39;8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd:0&#39;, &#39;value&#39;: 677200}, {&#39;output&#39;: &#39;bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786:0&#39;, &#39;value&#39;: 5000000}]
# Get the outputs of each transaction
&amp;gt;&amp;gt;&amp;gt; deserialize(fetchtx(&#39;8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd&#39;))[&#39;outs&#39;][0]
{&#39;value&#39;: 677200, &#39;script&#39;: &#39;a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287&#39;}
&amp;gt;&amp;gt;&amp;gt; deserialize(fetchtx(&#39;bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786&#39;))[&#39;outs&#39;][0]
{&#39;value&#39;: 5000000, &#39;script&#39;: &#39;a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287&#39;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Decoding the output script produces the following opcodes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;OP_HASH160 06612b7cb2027e80ec340f9e02ffe4a9a59ba762 OP_EQUAL
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which looks nothing like the common P2PKH output script described above. It looks like that ‘all’ that’s necessary to spend these outputs is to find a value that when hashed (with SHA-256 and then RIPEMD-160) matches &lt;code&gt;06612b7cb2027e80ec340f9e02ffe4a9a59ba762&lt;/code&gt;. However, it turns out that this is actually another type of transaction known as pay-to-script-hash (P2SH).&lt;/p&gt;

&lt;p&gt;In order to spend a P2SH output the scriptSig must push a serialized script, known as the redeemScript, onto the stack which has a hash that matches the one in the output script. If the hashes match, i.e. the &lt;code&gt;OP_EQUAL&lt;/code&gt; instruction in the output script has returned true, then the redeemScript is deserialized and evaluated. The transaction is valid if the redeemScript matches the expected hash and it returns true.&lt;/p&gt;

&lt;p&gt;Let’s look at some previous transactions from the target address and see what the redeemScript does:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Get an existing scriptSig
&amp;gt;&amp;gt;&amp;gt; deserialize(fetchtx(&#39;6102bfd4bad33443bcb99765c0751b6b8e4e65f4db4e3b65324c5e9e3dac8132&#39;))[&#39;ins&#39;][0]
{&#39;script&#39;: &#39;00483045022100e5d7c59ea1fb5d0285e755dfc09634e1e3af36d12950b9b5d5f92b136021b3d202202c181129443b08dcfb8d9ced30187186c57c96f9cdb3f3914e0798682ea35d2b03493046022100e1f8dbad16926cfa3bf61b66e23b3846323dcabf6c75748bcfad762fc50bfaf402210081d955160b5f8d2b9d09d8838a2cf61f5055009d9031e0e106e19ebab234d949034c695221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae&#39;, &#39;outpoint&#39;: {&#39;index&#39;: 1, &#39;hash&#39;: &#39;ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577&#39;}, &#39;sequence&#39;: 4294967295}
# Confirm that the corresponding output script matches the one discovered above
&amp;gt;&amp;gt;&amp;gt; deserialize(fetchtx(&#39;ec2a40cac3ac5dadf1d31f3cad03bdc8465caab5acbc5407ee7f4a7400aab577&#39;))[&#39;outs&#39;][1]
{&#39;value&#39;: 350000, &#39;script&#39;: &#39;a91406612b7cb2027e80ec340f9e02ffe4a9a59ba76287&#39;}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Decoding the scriptSig gets:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;OP_FALSE 304502... 304602... 5221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can manually verify that the final value that’s pushed onto the stack does match the expected hash in the output script:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; import hashlib
&amp;gt;&amp;gt;&amp;gt; data = &quot;5221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae&quot;.decode(&quot;hex&quot;)
&amp;gt;&amp;gt;&amp;gt; data = hashlib.sha256(data).digest()
&amp;gt;&amp;gt;&amp;gt; hashlib.new(&#39;ripemd160&#39;, data).hexdigest()
&#39;06612b7cb2027e80ec340f9e02ffe4a9a59ba762&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Therefore this is the redeemScript. Decoding it produces the following instructions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;2 023927... 03d2c0... 03ec01... 3 OP_CHECKMULTISIG
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;OP_CHECKMULTISIG&lt;/code&gt; takes a number of signatures and a number of public keys. Each signature and public key pair is checked with &lt;code&gt;OP_CHECKSIG&lt;/code&gt; for validity. In order for &lt;code&gt;OP_CHECKMULTISIG&lt;/code&gt; to return true all of the signatures must match one of the public keys. In this case there are two signatures which are provided by the scriptSig and three public keys which are included in the redeemScript. The &lt;code&gt;OP_FALSE&lt;/code&gt; instruction in the scriptSig is required due to a bug which means that &lt;code&gt;OP_CHECKMULTISIG&lt;/code&gt; removes an extra, unused value from the stack.&lt;/p&gt;

&lt;p&gt;Therefore, the target address is a multisignature wallet that has three associated public keys. In order to spend an output two valid signatures are required in the scriptSig (along with the redeemScript).&lt;/p&gt;

&lt;h2 id=&quot;signature-hash-types&quot;&gt;Signature hash types&lt;/h2&gt;

&lt;p&gt;Bitcoin supports transaction signatures that only validate portions of the transaction. There are three signature hash types:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;SIGHASH_ALL&lt;/code&gt;: All inputs and outputs are signed. This is the default signature hash type.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;SIGHASH_NONE&lt;/code&gt;: All of the inputs are signed, but none of the outputs are.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;SIGHASH_SINGLE&lt;/code&gt;: Only the corresponding input and output (the output with the same index number as the input) are signed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The signature hash type is specified by the last byte of a signature in the scriptSig. Transaction &lt;code&gt;6102bfd4...&lt;/code&gt; has three inputs. Here are the ends of the two signatures from each of the scriptSigs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;OP_FALSE ...5d2b03 ...d94903 &amp;lt;redeemScript&amp;gt;
OP_FALSE ...069803 ...182503 &amp;lt;redeemScript&amp;gt;
OP_FALSE ...7c2903 ...10b803 &amp;lt;redeemScript&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All of the signatures end in the value 0x03 which identifies them as SIGHASH_SINGLE signatures: the signature only covers the input itself and the output with the same index number. But there are three inputs and only two outputs; there is no corresponding output for the input with index two. What happens when it comes to creating the signature for this input?&lt;/p&gt;

&lt;p&gt;It turns out that, due to a bug, if an output with the same index does not exist then the integer value one will be returned as the hash of the transaction. This appears to have been first described by Peter Todd on the &lt;a href=&quot;https://bitcointalk.org/index.php?topic=260595.0&quot;&gt;bitcointalk forum&lt;/a&gt;. We can verify this behaviour in a Python shell:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt;&amp;gt;&amp;gt; pubs = [&#39;023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f0561196&#39;, &#39;03d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b80&#39;, &#39;03ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df&#39;]
&amp;gt;&amp;gt;&amp;gt; sigs = [der_decode_sig(&#39;3045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c2903&#39;), der_decode_sig(&#39;304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b803&#39;)]
&amp;gt;&amp;gt;&amp;gt; hash = &#39;\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00&#39;
&amp;gt;&amp;gt;&amp;gt; ecdsa_raw_verify(hash, sigs[0], pubs[0])
True
&amp;gt;&amp;gt;&amp;gt; ecdsa_raw_verify(hash, sigs[1], pubs[1])
True
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This means that it should be possible to forge a valid scriptSig for another transaction by reusing these signatures on inputs that do not have a corresponding output!&lt;/p&gt;

&lt;h2 id=&quot;stealing-coins-in-a-new-transaction&quot;&gt;Stealing coins in a new transaction&lt;/h2&gt;

&lt;p&gt;We want to create a transaction with a single output to an address that we control. This requires one input from an address we control to force the input index for the two inputs from the target transactions above zero. Here are the commands that I ran to create such a transaction:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# My address
&amp;gt;&amp;gt;&amp;gt; addr
&#39;1Lyafe8mSqubnynbAWPcXbHE5pnHMzEnT3&#39;
# Unspent transaction outputs (legitimately) under my control
&amp;gt;&amp;gt;&amp;gt; unspent(addr)
[{&#39;output&#39;: &#39;23e81960ba8bb95c33c2336c84c126e378e4d1123921f881da9247c25f524161:1&#39;, &#39;value&#39;: 300000}]
# Target address and unspent transaction outputs
&amp;gt;&amp;gt;&amp;gt; target = &#39;32GkPB9XjMAELR4Q2Hr31Jdz2tntY18zCe&#39;
&amp;gt;&amp;gt;&amp;gt; unspent(target)
[{&#39;output&#39;: &#39;8602122a7044b8795b5829b6b48fb1960a124f42ab1c003e769bbaad31cb2afd:0&#39;, &#39;value&#39;: 677200}, {&#39;output&#39;: &#39;bd992789fd8cff1a2e515ce2c3473f510df933e1f44b3da6a8737630b82d0786:0&#39;, &#39;value&#39;: 5000000}]
# The unspent outputs are the inputs to the new transaction
&amp;gt;&amp;gt;&amp;gt; ins = unspent(addr) + unspent(target)
# Amount to send in the transaction
# Sum of the three inputs minus a fee for the block miner
&amp;gt;&amp;gt;&amp;gt; amount = 300000 + 5000000 + 677200
&amp;gt;&amp;gt;&amp;gt; amount -= 10000
# Single output to my address
&amp;gt;&amp;gt;&amp;gt; outs = [{&#39;address&#39;: addr, &#39;value&#39;: value}]
# Create a new transaction from these inputs and outputs
&amp;gt;&amp;gt;&amp;gt; tx = mktx(ins, outs)
# Sign the first input with my private key
&amp;gt;&amp;gt;&amp;gt; tx = sign(tx, 0, priv)
&amp;gt;&amp;gt;&amp;gt; tx = deserialize(tx)
# Add the scriptSigs containing SIGHASH_SINGLE signatures of 1
&amp;gt;&amp;gt;&amp;gt; tx[&#39;ins&#39;][1][&#39;script&#39;] = &#39;00483045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c290347304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b8034c695221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae&#39;
&amp;gt;&amp;gt;&amp;gt; tx[&#39;ins&#39;][2][&#39;script&#39;] = &#39;00483045022100dfcfafcea73d83e1c54d444a19fb30d17317f922c19e2ff92dcda65ad09cba24022001e7a805c5672c49b222c5f2f1e67bb01f87215fb69df184e7c16f66c1f87c290347304402204a657ab8358a2edb8fd5ed8a45f846989a43655d2e8f80566b385b8f5a70dab402207362f870ce40f942437d43b6b99343419b14fb18fa69bee801d696a39b3410b8034c695221023927b5cd7facefa7b85d02f73d1e1632b3aaf8dd15d4f9f359e37e39f05611962103d2c0e82979b8aba4591fe39cffbf255b3b9c67b3d24f94de79c5013420c67b802103ec010970aae2e3d75eef0b44eaa31d7a0d13392513cd0614ff1c136b3b1020df53ae&#39;
&amp;gt;&amp;gt;&amp;gt; serialize(tx)
&#39;01000000036141525fc24792da81f8213912d1e478e326c18...&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I sent this pushed this transaction out onto the network: &lt;a href=&quot;https://blockexplorer.com/tx/791fe035d312dcf9196b48649a5c9a027198f623c0a5f5bd4cc311b8864dd0cf&quot;&gt;791fe035d312dcf9196b48649a5c9a027198f623c0a5f5bd4cc311b8864dd0cf&lt;/a&gt;. The coins were now mine!&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>The dangers of type coercion and remote management plugins</title>
        <link>http://joncave.co.uk/2013/03/dangers-of-type-coercion-and-remote-management/</link>
        <pubDate>Fri, 01 Mar 2013 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2013/03/dangers-of-type-coercion-and-remote-management/</guid>
        <description>&lt;p&gt;Remote management plugins are a popular tool among WordPress site administrators. They allow the user to perform the same action on multiple sites at once, e.g. updating to the latest release or installing a plugin. However, in order to perform these actions the client plugins need to provide a lot of power to a remote user. Therefore it is very important that the communication between the management server and the client plugin is secure and cannot be forged by an attacker. I decided to take a look at some of the available plugins for weaknesses that would allow an attacker to completely compromise a site running one of these plugins.&lt;/p&gt;

&lt;h2 id=&quot;managewp-infinitewp-and-cms-commander&quot;&gt;ManageWP, InfiniteWP, and CMS Commander&lt;/h2&gt;

&lt;p&gt;These three services share the same code base for the client plugin (I believe it’s originally authored by ManageWP and used by the other two with some tweaks) and so they were all vulnerable to a signature bypass that would allow remote code execution.&lt;/p&gt;

&lt;p&gt;Instead of requiring the user to provide administrator credentials, the management server registers a secret key with the client plugin which is used to compute a MAC for each message. A MAC is calculated by taking a message and passing it through a MAC algorithm along with a shared secret key. The message is then sent with the MAC attached. Finally, the recipient can recalculated the MAC of the sent message and check it against the MAC that was attached. MACs are used to verify the authenticity and integrity of a message, i.e. it was sent by the management server and has not been changed in transit. This is a good approach to securing communications, but implementation flaws in the client plugin for these three services lead to a critical security vulnerability.&lt;/p&gt;

&lt;p&gt;An incoming message is authenticated by &lt;code&gt;helper.class.php&lt;/code&gt; like this:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// $signature is the MAC sent with the message  &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// $data is part of the message  &lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get_random_signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;c1&quot;&gt;// valid message  &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The use of non-strict equality means that type juggling occurs before comparison. The output of the &lt;code&gt;md5()&lt;/code&gt; function is always a string, but if &lt;code&gt;$signature&lt;/code&gt; is an integer then the type coercion can make it relatively easy to forge a matching MAC. For example, if the true MAC starts with “0″ or a non-numeric character then the integer zero will match, if it starts “1x” (where “x” is non-numeric) then the integer 1 will match, and so on.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nb&quot;&gt;var_dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;abcdefg&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true  &lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;var_dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;1abcdef&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true  &lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;var_dump&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;2abcdef&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true  &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Unfortunately, an attacker &lt;em&gt;can&lt;/em&gt; provide an integer as a signature. In &lt;code&gt;init.php&lt;/code&gt; incoming requests are parsed by using &lt;code&gt;base64_decode()&lt;/code&gt; and then unserializing the result. The use of &lt;code&gt;unserialize()&lt;/code&gt; means that an attacker can provide types for the input data. An example of a forged, serialized message is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;a:4:{s:9:&quot;signature&quot;;i:0;s:2:&quot;id&quot;;i:100000;s:6:&quot;action&quot;;s:16:&quot;execute_php_code&quot;;s:6:&quot;params&quot;;a:2:{s:8:&quot;username&quot;;s:5:&quot;admin&quot;;s:4:&quot;code&quot;;s:25:&quot;exec(&#39;touch /tmp/owned&#39;);&quot;;}}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This message provides the signature as the integer 0 and uses the &lt;code&gt;execute_php_code&lt;/code&gt; action provided by the plugin to execute arbitrary PHP code.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$signature&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;c1&quot;&gt;// $data is the action concatenated with the message ID  &lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;execute_php_code&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get_random_signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;c1&quot;&gt;// valid message if the output of  &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// md5() doesn&amp;#39;t start with a digit  &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This example forgery is not guaranteed to work straight away. First of all the &lt;code&gt;id&lt;/code&gt; key needs to have a value greater than previous legitimate messages (the use of increasing message IDs is being used to prevent replay attacks). Secondly, a matching integer is required for the signature. These two requirements can be bruteforced relatively quickly:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for i from 100,000 to 100,500:
    for j from 0 to 9:
        submit request with id i and signature j
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This pseudocode will attempt to send fake messages with very large IDs and for each ID that is attempted ten single digit signatures are used to try and get a match.&lt;/p&gt;

&lt;p&gt;This flaw can be fixed by using strict equality (===) and performing other sanity checks on incoming signatures. Fixes were released only changing to strict equality by ManageWP on 19th February, InfiniteWP on 21st February, and CMS Commander on 28th February.&lt;/p&gt;

&lt;p&gt;A couple of other problems were reported, but they have not yet been acted on. First, the secret suffix MAC construction used (the secret key is appended to &lt;code&gt;$data&lt;/code&gt; and then hashed) has some weaknesses and &lt;a href=&quot;http://rdist.root.org/2009/10/29/stop-using-unsafe-keyed-hashes-use-hmac/&quot;&gt;HMAC should be used instead&lt;/a&gt;. Secondly, only the action and message ID are used to create a signature. This means that an active network attacker could change the parameters in a message and the signature would still be valid (e.g. change an &lt;code&gt;execute_php_code&lt;/code&gt; message to execute malicious code). To prevent this the MAC should cover the entire message.&lt;/p&gt;

&lt;p&gt;(Note that the MD5 based MAC algorithm is a fallback and these client plugins attempt to use &lt;code&gt;openssl_verify()&lt;/code&gt; where it is available.)&lt;/p&gt;

&lt;h2 id=&quot;worpit&quot;&gt;Worpit&lt;/h2&gt;

&lt;p&gt;Worpit is another remote management service, but it uses a client plugin built from scratch. It is also vulnerable to a type coercion bug that allows an attacker to log in with administrator privileges.&lt;/p&gt;

&lt;p&gt;This client plugin provides a method of remote administrator login “using temporary tokens only configurable by the Worpit package delivery system”. The plugin checks that the token provided in the request matches the one stored in the database:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_GET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;token&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$oWpHelper&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getTransient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;worpit_login_token&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;k&quot;&gt;die&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;WorpitError: Invalid token&amp;#39;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The token is deleted from the database once used. This means that most of the time there is no token in the database. Therefore the call to the &lt;code&gt;getTransient()&lt;/code&gt; method is likely to return &lt;code&gt;false&lt;/code&gt;. Non-strict comparison is used which means that any ‘falsey’ value, such as the string &lt;code&gt;0&lt;/code&gt;, will be treated as a valid token. An example URL to login as administrator:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;http://victim/?worpit_api=1&amp;amp;m=login&amp;amp;token=0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From here the site is completely compromised as the attacker has full privileges to install malicious plugins or edit existing ones.&lt;/p&gt;

&lt;p&gt;Again the fix is to use strict equality (!==) and to perform other sanity checks on the provided token and the one retrieved from the database. A fix was released on 10th February.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Always remember to check that user input is of the expected type and use strict comparison in security critical functions, such as checking authentication tokens.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Lying to Laravel</title>
        <link>http://joncave.co.uk/2012/10/lying-to-laravel/</link>
        <pubDate>Sat, 13 Oct 2012 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2012/10/lying-to-laravel/</guid>
        <description>&lt;p&gt;A vulnerability in the authentication system of the &lt;a href=&quot;http://laravel.com&quot;&gt;Laravel PHP framework&lt;/a&gt; allowed attackers to authenticate as any registered user.&lt;/p&gt;

&lt;p&gt;The authentication Driver base class uses a method called &lt;code&gt;recall()&lt;/code&gt; to retrieve a “remember me” cookie from the user. The cookie’s contents is decrypted, split on the ‘|’ character, and the first piece is taken as a user ID. This ID is then looked up in the database and if a matching record is found then the visitor is deemed to be authenticated as the corresponding user.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;sd&quot;&gt;/**&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt; * Attempt to find a &amp;quot;remember me&amp;quot; cookie for the user.&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt; *&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt; * @return string|null&lt;/span&gt;
&lt;span class=&quot;sd&quot;&gt; */&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;recall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;  
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
    &lt;span class=&quot;nv&quot;&gt;$cookie&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Cookie&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;recaller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;// By default, &amp;quot;remember me&amp;quot; cookies are encrypted and contain the user  &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// token as well as a random string. If it exists, we’ll decrypt it  &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// and return the first segment, which is the user’s ID token.  &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;is_null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;  
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;  
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;head&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;explode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;|&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Crypter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;decrypt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$cookie&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)));&lt;/span&gt;  
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;However, encryption isn’t authentication. An attacker is able to choose any ciphertext they wish and have the application attempt to decrypt it. So, ‘all’ that has to be done to authenticate as a user with a single digit ID is to find a ciphertext that decrypts to a digit followed by a ‘|’. Any random string can follow the pipe as it will be ignored by Laravel.&lt;/p&gt;

&lt;p&gt;Finding an appropriate ciphertext takes a relatively short amount of time with a bruteforce search. The attacker chooses two random strings with the same length as the block size of the cipher — Laravel uses Rijndael-256 so this is 32 bytes. These will be the initialisation vector (IV) and a block of ciphertext. A double loop is then run to try every combination of bytes for the first two bytes of the IV. On each iteration, the concatenation of the IV and ciphertext block are submitted to the target as the value of the “remember me” cookie. A check on the response from the application is used to determine if authentication occurred successfully, e.g. check for a string like “Welcome ”. If the cookie test returns true then the search is complete as a valid cookie has been found. Otherwise, the first two bytes of the IV are reset and the loop continues. The following is some pseudo-code that performs this search:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;iv &amp;lt;- 32 byte random string
ciphertext &amp;lt;- 32 byte random string

for i from 0 to 255:
  for j from 0 to 255:
    iv[0] ^= i
    iv[1] ^= j

    if check_cookie(iv + ciphertext):
      return iv + ciphertext

    iv[0] ^= i
    iv[1] ^= j
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This attack will take a maximum of 256 * 256 = 65536 requests to create an authenticator for a user with a single digit ID. From there it’s possible to authenticate as any single digit ID by working out which ID was forged and using this information to modify the first byte of the IV appropriately. The ID xor’d with the first by of the IV produces the first byte from the output of the block cipher. This value can then be xor’d with the target digit to get the new byte for the IV.&lt;/p&gt;

&lt;p&gt;Adding extra digits requires a maximum of 256 further requests per go. For example, to go from one to two digits you would modify the second byte of the IV to change the ‘|’ into a digit and then loop until a ‘|’ is produced at the third byte.&lt;/p&gt;

&lt;p&gt;The solution to this problem is to append a message authentication code (MAC) to cookies. This allows the application to verify that it created any received cookie data before it is used. Laravel has added MACs to cookies in 3.2.8 (released 26th September) and is using HMAC-SHA1 as the MAC algorithm.&lt;/p&gt;

&lt;p&gt;Interestingly, at the time of discovery, both the &lt;a href=&quot;https://github.com/laravel/laravel/blob/749948bc9d4c5f84d7c5e3ff5443efc823168615/laravel/documentation/input.md#cookies&quot;&gt;Laravel documentation&lt;/a&gt; and the &lt;a href=&quot;http://en.wikipedia.org/w/index.php?title=Laravel&amp;amp;oldid=493491884&quot;&gt;entry on Wikipedia&lt;/a&gt; listed “cookie tampering prevention” through the use of a “signature hash” as a feature. Unfortunately this was not actually the case.&lt;/p&gt;

&lt;p&gt;In the future, it would be good to see Laravel’s Crypter class have MACs built in so that all encrypted messages are verified before decryption. Examples of this type of behaviour can be seen in &lt;a href=&quot;https://github.com/zendframework/zf2/blob/bc94a43a6f6d9bb3f762bd2a76d84be9571c2328/library/Zend/Crypt/BlockCipher.php#L335&quot;&gt;Zend Framework 2&lt;/a&gt; and &lt;a href=&quot;https://github.com/zendframework/zf2/blob/bc94a43a6f6d9bb3f762bd2a76d84be9571c2328/library/Zend/Crypt/BlockCipher.php#L335&quot;&gt;Ruby on Rails&lt;/a&gt;.&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>I captured the flag!</title>
        <link>http://joncave.co.uk/2012/08/i-captured-the-flag/</link>
        <pubDate>Thu, 30 Aug 2012 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2012/08/i-captured-the-flag/</guid>
        <description>&lt;p&gt;Last week, Stripe launched their &lt;a href=&quot;https://stripe-ctf.com/about&quot;&gt;second capture the flag competition&lt;/a&gt;. Unlike the CTF they held in February, this version involved web-based vulnerabilities and exploits instead of lower-level problems. Also unlike the first CTF run by Stripe I was able to complete the last level and capture the flag!&lt;/p&gt;

&lt;p&gt;I know that there are many write-ups of all of the different levels already, so I just want to talk about the technical details of my favourite level.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Welcome to the penultimate level, Level 7.&lt;/p&gt;

  &lt;p&gt;WaffleCopter is a new service delivering locally-sourced organic waffles hot off of vintage waffle irons straight to your location using quad-rotor GPS-enabled helicopters. The service is modeled after TacoCopter, an innovative and highly successful early contender in the airborne food delivery industry. WaffleCopter is currently being tested in private beta in select locations.&lt;/p&gt;

  &lt;p&gt;Your goal is to order one of the decadent Liège Waffles, offered only to WaffleCopter’s first premium subscribers.&lt;/p&gt;

  &lt;p&gt;Log in to your account at https://level07-2.stripe-ctf.com/user-xxxxxxxxxx with username ctf and password password. You will find your API credentials after logging in.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Looking at the code for level 7 showed that the &lt;code&gt;/orders&lt;/code&gt; API endpoint didn’t have any obvious way to bypass signature verification or order premium waffles as the &lt;code&gt;ctf&lt;/code&gt; user. So, I started to look elsewhere. Almost immediately I spotted that although the &lt;code&gt;/logs/:id&lt;/code&gt; route requires authentication it doesn’t stop authenticated users from viewing the API request logs of other users. By visiting &lt;code&gt;/logs/1&lt;/code&gt; it’s possible to view the requests of a premium user ordering some waffles. Unfortunately they hadn’t ordered the target Liège waffle so it seems that all that can be done is replay requests for unwanted waffles, right?&lt;/p&gt;

&lt;p&gt;At this point I had to leave to walk to work. This turned out to be a good thing, on this ‘ponder wander’ I realised that, whilst investigating the benefits of &lt;a href=&quot;http://en.wikipedia.org/wiki/Hash-based_message_authentication_code&quot;&gt;HMAC&lt;/a&gt; in the past, I had read about attacks on the signature creation method that was being employed. If it’s possible to take an old request from a premium user, change the ordered waffle to the target and then create a valid MAC then the password can be found.&lt;/p&gt;

&lt;h2 id=&quot;length-extension-attacks&quot;&gt;Length extension attacks&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;verify_signature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# get secret token for user_id&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;users&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NotFound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BadSignature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;no such user_id&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;secret&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hashlib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sha1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;raw_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;computed signature&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;for body&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;repr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;raw_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BadSignature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;signature does not match&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Above is the code used by the &lt;a href=&quot;https://gist.github.com/3544137&quot;&gt;WaffleCopter server&lt;/a&gt; to verify a signed request. The signature for a request is calculated by taking the body of the request (the message), appending it to the user specific secret and computing the SHA-1 hash of the result. This is a weak method of creating a MAC because for some hash functions, like SHA-1, it is possible to compute &lt;code&gt;H(m || padding(m) || m&#39;)&lt;/code&gt; for any &lt;code&gt;m&#39;&lt;/code&gt; given &lt;code&gt;H(m)&lt;/code&gt; where where &lt;code&gt;m&lt;/code&gt; is unknown (&lt;code&gt;||&lt;/code&gt; denotes concatenation).&lt;/p&gt;

&lt;p&gt;Length extension is possible on all hash functions that make use of the &lt;a href=&quot;http://en.wikipedia.org/wiki/Merkle–Damgård_construction&quot;&gt;Merkle–Damgård construction&lt;/a&gt; to build a hash function which accepts arbitrarily sized input from a one-way compression function that only accepts fixed size inputs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2012/08/Merkle-Damgard-hash-construction.png&quot; alt=&quot;Merkle-Damgård hash construction&quot; title=&quot;Merkle-Damgård hash construction&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The image above shows the construction of a hash function from a one-way compression function &lt;code&gt;f&lt;/code&gt; which takes fixed size two inputs and produces a fixed sized output the same size as one of the inputs. First, the input message is broken up into blocks of the correct size. The compression function is repeatedly applied to successive blocks of the input message along with the output of the previous function application. The first message block is compressed along with a public initialization vector (IV) that is algorithm specific. The final block is padded as necessary so that it is the appropriate size for the compression function. The result of the final compression is the hash for the input message.&lt;/p&gt;

&lt;p&gt;It should now be pretty easy to see how &lt;code&gt;H(m || padding(m) || m&#39;)&lt;/code&gt; can be calculated for an arbitrary &lt;code&gt;m&#39;&lt;/code&gt; given &lt;code&gt;H(m)&lt;/code&gt;. It is computed by producing &lt;code&gt;H(m&#39;)&lt;/code&gt; but with the value of &lt;code&gt;H(m)&lt;/code&gt; being used in place of the hash function’s standard initialization vector.&lt;/p&gt;

&lt;p&gt;With this knowledge it is now possible to create a valid MAC when &lt;code&gt;MAC = H(K   M)&lt;/code&gt; where &lt;code&gt;K&lt;/code&gt; is a secret and &lt;code&gt;M&lt;/code&gt; is the message. All that needs to be known is the length of &lt;code&gt;K&lt;/code&gt; and any message &lt;code&gt;M&lt;/code&gt; and its associated MAC &lt;code&gt;C&lt;/code&gt;. This is done by working out the padding that the hash function would add automatically during the computation of &lt;code&gt;C&lt;/code&gt; and appending it to &lt;code&gt;M&lt;/code&gt;: &lt;code&gt;M&#39; = M || padding&lt;/code&gt;. The amount of padding to use is determined by adding the lengths of &lt;code&gt;K&lt;/code&gt; and &lt;code&gt;M&lt;/code&gt; modulo the block size required by the compression function. Extra data can then be appended to create &lt;code&gt;M&#39;&#39; = M&#39; || extra&lt;/code&gt;. The valid MAC for our new message &lt;code&gt;M&#39;&#39;&lt;/code&gt; is &lt;code&gt;H(M&#39;&#39;)&lt;/code&gt; when using &lt;code&gt;C&lt;/code&gt; as the value of the IV.&lt;/p&gt;

&lt;p&gt;So, back to level 7 of the Stripe CTF. Take one of the signed API requests for a premium user:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;count=10&amp;amp;lat=37.351&amp;amp;user_id=1&amp;amp;long=-119.827&amp;amp;waffle=eggo|sig:11de8a0bc70d80ffe6b25d34c0711cd450ebdd29
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;M&lt;/code&gt; is the piece before the pipe and &lt;code&gt;C&lt;/code&gt; is the piece after “sig:”. The extra data to extend the message with is &lt;code&gt;&amp;amp;#038;waffle=liege&lt;/code&gt; so that the requested waffle parameter in the original message is overwritten with the name of the target. By using the length extension attack described above it’s possible to create &lt;code&gt;M&#39;&#39;&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;count=10&amp;amp;lat=37.351&amp;amp;user_id=1&amp;amp;long=-119.827&amp;amp;waffle=eggo\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x28&amp;amp;waffle=liege
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and a valid MAC:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;37c9dcaef9a370feb2daf97211a1bbb273812753
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The password for level 8 could then be found by POSTing the concatenation of &lt;code&gt;M&#39;&#39;&lt;/code&gt;, “|sig:” and the new MAC to the orders API endpoint. The request will be verified as having been made by user 1 (a premium user) ordering a Liège waffle.&lt;/p&gt;

&lt;p&gt;During the CTF I created the extended message and its MAC by taking a Python implementation of SHA-1 and hacking up it’s internal state. This was much harder than it could have been as it turns out that there is an &lt;a href=&quot;http://www.vnsecurity.net/t/length-extension-attack/&quot;&gt;existing tool&lt;/a&gt; for creating extended messages and new MACs.&lt;/p&gt;

&lt;p&gt;Overall the CTF was thoroughly enjoyable and I hope that Stripe (and others) continue to create these fun security challenges in the future.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>make/plugins endpoints API tutorial</title>
        <link>http://joncave.co.uk/2012/06/makeplugins-endpoints-api-tutorial/</link>
        <pubDate>Thu, 07 Jun 2012 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2012/06/makeplugins-endpoints-api-tutorial/</guid>
        <description>&lt;p&gt;Today I posted a &lt;a href=&quot;http://make.wordpress.org/plugins/2012/06/07/rewrite-endpoints-api/&quot;&gt;tutorial on the make.wordpress.org/plugins site&lt;/a&gt; about how to use the WordPress rewrite endpoints API and detail on how they work internally.&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>Trac Cookie Revocation</title>
        <link>http://joncave.co.uk/2011/10/trac-cookie-revocation/</link>
        <pubDate>Wed, 26 Oct 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/10/trac-cookie-revocation/</guid>
        <description>&lt;p&gt;Last week there was some spam posted to the WordPress core &lt;a href=&quot;http://core.trac.wordpress.org/&quot; title=&quot;WordPress Trac&quot;&gt;bug tracker&lt;/a&gt;. The accounts involved can easily have their access to WordPress.org blocked and their passwords changed to invalidate the cookies used to access the WordPress.org forums. This also stops them from logging into the bug tracker again. However, the &lt;code&gt;trac_auth&lt;/code&gt; cookie — the cookie that Trac uses to authenticate a browser to a particular user account after valid login details are provided — is not tied to a user’s password; instead the cookie stores a random string that can be verified against the &lt;code&gt;auth_cookie&lt;/code&gt; table in the Trac database. This means that until this cookie expires, when the user closes their browser or 10 days after initial sign-on, the spammer is able to remain authenticated to their WordPress.org profile on core.trac.wordpress.org and can continue to post their spam on the bug tracker.&lt;/p&gt;

&lt;p&gt;So, because I was curious (and I had to find something to do other than revision for a machine learning test on Tuesday), I decided to write a short Trac plugin to allow a &lt;code&gt;TRAC_ADMIN&lt;/code&gt; user to revoke user cookies. The plugin registers a new administration panel and provides the HTML template for its display. The new panel is just a simple form with a single input for entering the target’s username. After the form is submitted the plugin handles the POST request to delete the row in the &lt;code&gt;auth_cookie&lt;/code&gt; table which matches the given name. On future requests to the Trac instance the value stored in the user’s &lt;code&gt;trac_auth&lt;/code&gt; cookie will no longer match an entry in the database and so the user will not be authenticated.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2011/10/revoke-a-cookie.png&quot; alt=&quot;Revoking a trac_auth cookie&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The code can be found on &lt;a href=&quot;http://github.com/joncave/Trac-Cookie-Revocation&quot;&gt;github&lt;/a&gt;. Currently the master branch and the 0.1 tag can be run with Trac versions greater than 0.12 whilst the develop branch contains a small update to make use of enhancements to the Trac database API in the unreleased Trac 0.13.&lt;/p&gt;

&lt;p&gt;I found the process of writing a Trac plugin to be quite interesting and fun. Using my (basic) python knowledge again was a good experience too. I already have a project lined up which requires a Trac plugin to be developed, so this was also a nice, easy way to set up the necessary &lt;a href=&quot;http://trac.edgewall.org/wiki/TracDev/DevelopmentEnvironmentSetup&quot;&gt;development environment&lt;/a&gt; in advance and get myself acquainted with &lt;a href=&quot;http://trac.edgewall.org/wiki/TracDev&quot;&gt;the API&lt;/a&gt;.&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>One year in core</title>
        <link>http://joncave.co.uk/2011/04/one-year-in-core/</link>
        <pubDate>Sun, 10 Apr 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/04/one-year-in-core/</guid>
        <description>&lt;p&gt;A year ago today was the first time that one of my patches was &lt;a href=&quot;http://core.trac.wordpress.org/changeset/14057&quot;&gt;accepted&lt;/a&gt; into WordPress core. Just a few days after submitting my first patch and opening my first ticket.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2011/04/r14057.png&quot; alt=&quot;Changeset 14057&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the past twelve months I have submitted hundreds of other patches and been involved with a few other projects outside of the core. I have also helped it with, if not been one of the causes of, the past four security releases — sorry folks.&lt;/p&gt;

&lt;p&gt;It has been truly amazing to be involved with the community and to know that I have helped make software that is used by millions daily. It is also the first time that I can honestly say that I was glad to have had revision to do. In trying to procrastinate and put off doing said revision I decided to contribute to an open source project. I chose WordPress.&lt;/p&gt;

&lt;p&gt;My goals for the second year? Firstly to be more involved with the WordPress community; for starters I need to attend my first WordCamp as I feel that I have really missed out on that front so far. Second, to help get more people contributing to the project. This is currently taking the form of being a GSoC mentor this year. Last, and definitely not least, to continue contributing as much as I can to WordPress. This means many, many more patches as well as finding the time to work more on the &lt;a href=&quot;http://code.svn.wordpress.org/dotorg-api-reference/&quot;&gt;WordPress API reference&lt;/a&gt;.&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>Announcing Exploit Scanner 1.0</title>
        <link>http://joncave.co.uk/2011/02/announcing-exploit-scanner-1-0/</link>
        <pubDate>Sun, 27 Feb 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/02/announcing-exploit-scanner-1-0/</guid>
        <description>&lt;p&gt;With the launch of WordPress 3.1 — actually slightly delayed by bug hunting — I am pushing Exploit Scanner version 1.0.&lt;/p&gt;

&lt;p&gt;Summary of main changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;diffs of modified core WordPress files&lt;/li&gt;
  &lt;li&gt;File hashes for WordPress 3.1&lt;/li&gt;
  &lt;li&gt;Updated malicious pattern signatures&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;core-file-diffs&quot;&gt;Core file diffs&lt;/h3&gt;

&lt;p&gt;The major feature delivered with the new release are diffs of core file changes. This allows you to easily see how a modified file has been changed from the original and identify any malicious code that has been introduced.&lt;/p&gt;

&lt;p&gt;These diffs are powered by the same engine that runs the &lt;a href=&quot;http://thinkvitamin.com/asides/how-to-use-wordpress-revisions-to-go-back-in-time/&quot;&gt;compare revisions&lt;/a&gt; feature in WordPress; that is Text Diff from The Horde Project and PHP PEAR.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2011/02/exploit-scanner-diff.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Understanding the output is relatively simple. First of all the pretty colours quickly show you what has been added or removed from the file in question. Red indicates content that has been removed from the original, unmodified core file. Green highlights lines that have been added to a file. There are also reference numbers along with ‘change commands’ detailing the line numbers affected. There are &lt;a href=&quot;http://www.gnu.org/software/diffutils/manual/#Detailed-Normal&quot; title=&quot;GNU diffutils manual&quot;&gt;three of these change commands&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;l&lt;/em&gt;a&lt;em&gt;r&lt;/em&gt; — Add the lines in range &lt;em&gt;r&lt;/em&gt; of modified file after line &lt;em&gt;l&lt;/em&gt; of the original file.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;f&lt;/em&gt;c&lt;em&gt;t&lt;/em&gt; — Replace the lines in range &lt;em&gt;f&lt;/em&gt; of the original file with the lines in range &lt;em&gt;t&lt;/em&gt; of the modified file.&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;r&lt;/em&gt;d&lt;em&gt;l&lt;/em&gt; — Delete lines in the range &lt;em&gt;r&lt;/em&gt; of the original file; line &lt;em&gt;l&lt;/em&gt; is the line where they would have appeared in the modified file if they had not been removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This feature works by retrieving the unmodified source file from the WordPress subversion repository and comparing it to the local file using Text Diff. Unmodified sources are cached in the database to reduce HTTP requests and (minimal) extra load on the WordPress.org servers.&lt;/p&gt;

&lt;h3 id=&quot;plans-for-the-future&quot;&gt;Plans for the future&lt;/h3&gt;

&lt;p&gt;Bug fixing and continued core hash updates as usual. Unfortunately people still seem to encounter problems when running scans, but I never seem to be able to reproduce and pinpoint how the error is occurring. 1.0 adds some error catching code to help track this.&lt;/p&gt;

&lt;p&gt;wp-config.php tracking. Changes to core files are easily spotted with checksums and the new diffs feature, but the all important wp-config.php file is not tracked. This probably would not be limited to just the config file, but could be extended to all files that make up your WordPress installation (i.e. plugins, themes, etc.) and would allow you to detect any modifications made from a known clean state &lt;em&gt;à la&lt;/em&gt; &lt;a href=&quot;http://aide.sourceforge.net/&quot;&gt;AIDE&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the air signature updates and patches are really interesting to me. I have been toying with the idea providing (semi-)automatic updates to the malicious code signatures and even core patches for security vulnerabilities — though the latter may best be left to the &lt;a href=&quot;http://vaultpress.com&quot; title=&quot;VaultPress&quot;&gt;VaultPress team&lt;/a&gt; (sidenote: is there going to be a public release of the &lt;a href=&quot;http://blog.vaultpress.com/2010/03/30/announcing/#comment-109&quot;&gt;plugin&lt;/a&gt; at some point?). This is the least likely update for the near future and would most probably be an optional feature as it would involve pinging an update server. A pipe dream for now.&lt;/p&gt;

&lt;p&gt;Let me know if there is anything you would like – or not like – to see in future versions of Exploit Scanner.&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>Road to WordPress 3.1</title>
        <link>http://joncave.co.uk/2011/02/road-to-wordpress-3-1/</link>
        <pubDate>Wed, 23 Feb 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/02/road-to-wordpress-3-1/</guid>
        <description>&lt;p&gt;WordPress 3.1 is finally &lt;a href=&quot;http://wordpress.org/news/2011/02/threeone/&quot; title=&quot;WordPress 3.1, lots of fun&quot;&gt;here&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;Of the new features that arrived today, a few of my favourites are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Internal linking&lt;/li&gt;
  &lt;li&gt;Improved WXR import/export (well it had to be on &lt;a href=&quot;http://core.trac.wordpress.org/ticket/15197&quot; title=&quot;WXR export/import umbrella ticket&quot;&gt;my&lt;/a&gt; list)&lt;/li&gt;
  &lt;li&gt;Admin bar, just because of the awesome &lt;a href=&quot;http://wordpress.org/extend/plugins/debug-bar/&quot; title=&quot;Debug Bar WordPress plugin&quot;&gt;Debug Bar plugin&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following is a visualization of all the commits made to WordPress up until the release of 3.1:&lt;/p&gt;

&lt;div class=&quot;embed-container video &quot;&gt;&lt;iframe src=&quot;https://player.vimeo.com/video/20301230&quot; width=&quot;640&quot; height=&quot;480&quot; frameborder=&quot;0&quot; title=&quot;Road to WordPress 3.1&quot; webkitallowfullscreen=&quot;&quot; mozallowfullscreen=&quot;&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;The video was made using &lt;a href=&quot;http://code.google.com/p/gource/&quot; title=&quot;Gource&quot;&gt;Gource&lt;/a&gt; on a checkout of the whole WordPress repository using the following commands.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;`gource --log-command svn` &amp;gt; svn.log
gource --user-image-dir gravatars --disable-progress --stop-at-end --highlight-users -s 0.1 --date-format &#39;%A, %e %B %Y&#39; --output-ppm-stream - svn.log | ffmpeg -b 3000K -r 60 -f image2pipe -vcodec ppm -i - -vcodec libx264 -vpre medium wp-gource.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unfortunately the commits appear to lose sync with the date. There are only four commits in the log for 23 February 2011, but the video shows some from a few days before. However since it took so long to create the video the first time I was not going to try again!&lt;/p&gt;

&lt;p&gt;Time to &lt;a href=&quot;http://trac.wordpress.org/changeset/17488&quot; title=&quot;3.2-bleeding&quot;&gt;start work&lt;/a&gt; on 3.2!&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>Password reminders or: How not to instill confidence</title>
        <link>http://joncave.co.uk/2011/01/password-reminders/</link>
        <pubDate>Mon, 17 Jan 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/01/password-reminders/</guid>
        <description>&lt;p&gt;Please do not do this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/2011/01/password-reminder.png&quot; alt=&quot;Password reminder email&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Either send me a random string and tell me to change it once successfully logged in (not great), or send a link to allow me to save a new &lt;strong&gt;secret&lt;/strong&gt; password.&lt;/p&gt;

&lt;p&gt;Definitely do not let me believe that my password is being stored in plain text in a database (which is what this situation indicates), instead of being stored after the application of a one-way hash function with &lt;a href=&quot;http://joncave.co.uk/2011/01/password-storage-in-drupal-and-wordpress/&quot;&gt;salting and stretching&lt;/a&gt;.&lt;/p&gt;

</description>
      </item>
    
      <item>
        <title>Drupal 7: Secure password storage by default at last</title>
        <link>http://joncave.co.uk/2011/01/password-storage-in-drupal-and-wordpress/</link>
        <pubDate>Wed, 05 Jan 2011 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2011/01/password-storage-in-drupal-and-wordpress/</guid>
        <description>&lt;p&gt;With the release of &lt;a href=&quot;http://drupal.org/7&quot;&gt;Drupal 7&lt;/a&gt; today we see the arrival of secure password storage by default (as well as &lt;a href=&quot;http://drupalcode.org/viewvc/drupal/drupal/CHANGELOG.txt?revision=1.396&amp;amp;view=markup&quot;&gt;many other&lt;/a&gt; great new features and changes). Obviously secure password storage in the database is essential for any web application. The most recent high-publicity example of weak password storage was the &lt;a href=&quot;http://www.lightbluetouchpaper.org/2010/12/15/the-gawker-hack-how-a-million-passwords-were-lost/&quot;&gt;Gawker break in&lt;/a&gt;; thousands of users had their passwords recovered from the DES hashes and, &lt;a href=&quot;http://imgs.xkcd.com/comics/password_reuse.png&quot;&gt;as we know&lt;/a&gt;, these are likely to be passwords used everywhere. Previous versions of Drupal have simply been storing the MD5 hash of a user’s password in the database. But why is this dangerous?&lt;/p&gt;

&lt;p&gt;MD5 is a cryptographic hash function and so it &lt;em&gt;should&lt;/em&gt; be infaesible to find a plaintext for a given hash. However, there are two main problems with a simple application of MD5 when storing passwords. (Both unrelated to known weaknesses, such as collision attacks, in MD5.)&lt;/p&gt;

&lt;p&gt;The first problem is that it is easy to precompute MD5 hashes for a vast number of input strings and store these in a &lt;a href=&quot;http://en.wikipedia.org/wiki/Rainbow_table&quot;&gt;rainbow table&lt;/a&gt;. Such a table can then be used to quickly lookup a hash and find the original password. The example figures given by the &lt;a href=&quot;http://project-rainbowcrack.com/table.htm&quot;&gt;RainbowCrack project&lt;/a&gt; suggest that a match can be found for a 7-character password made up from the original 95 ASCII characters, e.g. “@dtE]e~”, in under 10 minutes on an average desktop machine using a 64GB table.&lt;/p&gt;

&lt;p&gt;The (very old) fix for this is to &lt;a href=&quot;http://en.wikipedia.org/wiki/Salting_(cryptography)&quot;&gt;salt&lt;/a&gt; password hashes. This is done by generating a small, random bit sequence, this is the salt, and adding it to the password before it is hashed. The salt is then stored as plaintext along with the password hash. Now the application can still verify a submitted password, but it has made the use of rainbow tables impractical. For example, a small salt of length 16-bits has 2&lt;sup&gt;16&lt;/sup&gt; = 65,536 different variations, each of which has to be computed and added to every single possible password (of which there are already billions) to build a rainbow table of the same usefulness. That 64GB table now has to become unconceivably big to be of any effective use against moderately strong passwords.&lt;/p&gt;

&lt;p&gt;Second problem: MD5 is a quick function to compute (one of the desired features of cryptographic hash functions). So even without a rainbow table it is possible to start trying to brute force a password by generating MD5 hashes on the fly looking for a match. &lt;a href=&quot;http://www.openwall.com/john/&quot;&gt;John the Ripper&lt;/a&gt;, once patched to crack simple single MD5 password storage, can check the MD5 hashes of approximately 5,720,000 passwords per second on my laptop (2.4GHz Core i5, 4GB RAM). John the Ripper, and other similar tools, make use of time to crack passwords; the amount of time taken depends on the character set or dictionary that is used by the cracker, and even salted passwords can be cracked relatively quickly (2,200,000 passwords attempted per second for traditional-DES crypt passwords).&lt;/p&gt;

&lt;p&gt;The solution to this is to use password stretching to increase the amount of time it takes to calculate hash of a password. Instead of running the hash function once it is run for thousands of iterations. This means that to check for a match a cracking tool now needs to run the thousands of hash iterations on each candidate password, thus greatly slowing the progress of the program and diminishing its usefulness.&lt;/p&gt;

&lt;p&gt;So, salting and stretching together make a strong solution to password storage. And here to save the day is &lt;a href=&quot;http://www.openwall.com/phpass/&quot;&gt;phpass&lt;/a&gt; from solardesigner (also author of John the Ripper), included in WordPress &lt;a href=&quot;http://core.trac.wordpress.org/changeset/6350&quot;&gt;since 2.5&lt;/a&gt; and now (well, quite a &lt;a href=&quot;http://drupal.org/cvs?commit=108551&quot;&gt;while&lt;/a&gt; &lt;a href=&quot;http://drupal.org/cvs?commit=108603&quot;&gt;ago&lt;/a&gt; actually) in Drupal 7 (though modified to use SHA-512 instead of MD5)…&lt;/p&gt;

&lt;p&gt;The MD5 mode, a.k.a. portable hashes mode, of phpass works by generating an 8 character random salt which is prepended to the password and hashing the resulting string with MD5. This process is then repeated for several thousand iterations with the previous hash taking the place of the random salt in the first application of MD5.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-php&quot; data-lang=&quot;php&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$salt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$hash&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TRUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The whole final hash value is encoded into 16 base64 characters and prepended by an identifying string, the standard phpass MD5 mode uses $P$ (Drupal’s modified version uses $S$ to indicate SHA-512) and a single base64 character to indicate the number of MD5 iterations used. Examples of a hashed password are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Drupal 7 hash
$S$CgwilRJS4VIF1.2y0R7B4qkXJ8F8SJPcuvXRKGlMWESVXMST.5n4
# WordPress 3.0.4 hash
$P$BiutJFaIcFHm5Vl286atS1.Tm1Advv0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;WordPress 3.0.4 uses the phpass default of 8193 iterations ($count being 8192) and Drupal 7 uses 16385 — notice that the Drupal password has C after the identifier whereas WordPress has B, converted from crypt style base64 (character set [./0-9A-Za-z]) these are 14 and 13 respectively, then take 2&lt;sup&gt;14&lt;/sup&gt; + 1 = 16385. A John the Ripper benchmark, after patching and enabling the usage of phpass portable passwords (WordPress style, 8193 iterations), quotes approximately 700 passwords checked per second.&lt;/p&gt;

&lt;p&gt;Remember, always use a library written by somebody else (who is smart at crypto), use salting and stretching, and always use strong passwords as phpass will not save you from weak passwords and password reuse.&lt;/p&gt;

&lt;p&gt;Further reading for those still interested:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.openwall.com/articles/PHP-Users-Passwords&quot;&gt;How to manage a PHP application’s users and passwords&lt;/a&gt; by solardesigner&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html&quot;&gt;What You Need To Know About Secure Password Schemes&lt;/a&gt; by Thomas Ptacek&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are good explanations of secure password storage, password stretching and why you should use a library such as phpass or bcrypt (the latter being the one recommended by Ptacek).&lt;/p&gt;
</description>
      </item>
    
      <item>
        <title>I see your WordPress 3.0.4 with Exploit Scanner 0.97.5</title>
        <link>http://joncave.co.uk/2010/12/updates-galore/</link>
        <pubDate>Thu, 30 Dec 2010 00:00:00 UTC</pubDate>
        <author>Jon Cave</author>
        <guid>http://joncave.co.uk/2010/12/updates-galore/</guid>
        <description>&lt;p&gt;WordPress 3.0.4 was &lt;a href=&quot;http://wordpress.org/news/2010/12/3-0-4-update/&quot;&gt;released a few hours&lt;/a&gt; ago to fix a couple of persistent XSS vulnerabilities. One of these was discovered by me, and I also participated in lengthy discussions about the fix (maybe more on this at a later date). It is strongly recommended that you update now as this is a critical security release.&lt;/p&gt;

&lt;p&gt;I have just pushed an update to &lt;a href=&quot;http://wordpress.org/extend/plugins/exploit-scanner/&quot;&gt;Exploit Scanner&lt;/a&gt; with a new set of hashes for WordPress 3.0.4. The update also removes the wp-content folder and sub-directories/files from the list of core file hashes. This was done because of the difference in the release cycles of WordPress and Akismet; Akismet 2.4.0 got included in the 3.0.4 package, however 2.5.1 is the current stable version (hopefully this will be addressed by a change in core in the future, maybe either dropping it from the package and/or never touching wp-content on updates only initial installs).&lt;/p&gt;

&lt;p&gt;I plan on releasing the next ‘major’ version of Exploit Scanner to coincide with the release of 3.1. The main new feature, which has actually been sitting in trunk for quite a while, will be core file diffs. This will allow you to see exactly what has changed if the plugin detects a modified core WordPress file. Please download the &lt;a href=&quot;http://downloads.wordpress.org/plugin/exploit-scanner.zip&quot;&gt;development version&lt;/a&gt; and give it some thorough testing if you feel like trying out the new goodness.&lt;/p&gt;

</description>
      </item>
    

  </channel>
</rss>
