Saturday, October 11, 2014

Web Hacking 101: HTML Editing

Editing the HTML can reveal various security flaws or basic issues with a website. You can use it to reveal hidden information or alter a form's behavior or limitations. This will probably prove the most useful with forms.

The tools required to accomplish this can be Javascript or various addons like Firebug. To understand how to do so with Javascript, it requires a basic understanding of Javascript and DOM. Either method you choose, console addons like Firebug can be very useful, as to avoid putting everything in a Javascript injection.

Most modern browsers now also include built-in inspection tools that allow easy HTML editing as well. These tools are quite handy, but can vary from browser to browser. most often, they can be accessed with a right click, selecting the "Inspect Element" option. You can then edit stuff with a double click on the area of stuff that pops up in the inspector.

So let's look at this with a simple HTML form page I made and editing on Firefox. Here's the code for it.

<!DOCTYPE html>
<html>
    <head>
        <title>Stuff</title>
    </head>
    <body>
        <form>
            <input type="hidden" value="false" name="admin" />
            Enter Password: <input name="pwd" type="password" />
        </form>
    </body>
</html>

First we right click on the element we want and select "Inspect Element" like so.


This should result in something popping up at the bottom. If it's on the wrong thing, just try using the drop down arrows to get to where you need to be.

Then to edit a specific thing, we just double click on it. For example, the "Enter Password:" text.

Let's make this look a little nicer, shall we?



For those paying close attention, you may notice something that doesn't show up on the visible potion of the form. A hidden form element. I made the value quite obvious what it's to do. So how about we change this? Quite simple to do, just double click the part you want to edit, same as before!


Now this is the easiest way to simply alter HTML on your end. While editing things might not be as easy as something this simple or have something as golden as that hidden element, it can still be useful. Much like viewing the source, we get to see the cool hidden stuff, with the added bonus of being able to make alterations and navigate in this handy drop-down fashion with directed right clicking action.

The easy way is fine and dandy, but sometimes it may be better to use Javascript. The reason being is we can add more stuff, like event listeners, have access to variable in the Javascript code itself, add or alter things logically or really anything you could do making your own HTML page with Javascript. All we need to do this is knowledge of Javascript! So either go learn it or enjoy knowing it already.

For the case of this form, we can simply put in the address bar this little snippet. I should mention that in some browsers, this may be disabled or run into some issues for security reasons. The built in console is always an option.

javascript:document.forms[0].admin.value="true";void(0)

Now, like magic, we have altered the value. It's as simple as though you wrote the Javascript code on the page yourself. All we had to do was add "javascript:" to the front to run it in the address bar. Oh, and the void function is necessary because stuff happens. Alternatively, you can use the console on the inspector tool and not need the prefix or the void function, but do note that having void in there won't harm anything. Now the only limit is your imagination... and Javascript skills and Javascript's limitations.

While on the subject, the Firefox addon called Greasemonky, included in my collection of must have tools (more info here), can run code for you when loading a site through userscripts. Can be quite handy should some code alter stuff when the site loads and gets in your way.

Wednesday, September 3, 2014

Web Hacking 101: robots.txt

Here's a pretty specific trick that may get you somewhere or nowhere. However, it is good to see things from all angles. Now a robots.txt file is not required for websites, but it is often included to keep web crawlers and other indexing tools that bother to check, in check. It gives directives of how fast to move around and where it is allowed or not.

Our main interest is in where it tells bots not to go. The reason being, there may be something useful in there. A robots.txt file may look something like so.

User-agent: *
Disallow: /secrets/
Crawl-delay: 5

The general rule of thumb is you only disallow exposed links, as bots generally crawl exposed links only. They won't go finding something that does not have an obvious path. Yet, still people insist on putting there secret folders and such on a file that anyone can access, thus revealing secret areas.

A while ago, someone posted a link on a chat. The link was to download software that the website had set up so that you are supposed to pay for it. The problem was, they put the directory with the software in the robots.txt file and there was nothing stopping a direct download. So it was free software for the taking.

My personal experience has been that most of the time, the areas are dead, or at least appear to be. My guess is it is because most people don't feel the need to keep this up-to-date. Either way, there is a chance it will expose more of the site to you than meets the eye.

Sunday, August 24, 2014

Web Hacking 101: URL/URI Modification

Modifying a URI is very simple and can be an easy way to break things or do things you might not normally be able to. The main thing people always seem to mix up is a URL and a URI. A URL is quite simply the domain.

example.com
www.example.com

A URI contains all the other information. This information can be broken down into lots of useful information. The URI contains the protocol, domain, directory location, file, port, anchor, and query string. A lot of this stuff is optional, like a directory location, file, port, query string, anchor and most browsers don't need a protocol unless it's something other than HTTP. Here's the breakdown.

protocol://subdomain.domain.topLevelDomain:port/path/to/file.extension?query=string&with=multipleValues#anchor

Common protocols you will see are HTTP (Hyper text transport protocol), HTTPS (http with TLS/SSL encryption), and FTP (file transfer protocol). Modern browsers figure out what port to use based on the protocol, making including the port unnecessary unless it does not use the default protocol port. The file protocol can also be used to browse local files on your computer.

Domains are broken down into subdomains, domains and top level domains. The top level domains have meanings but most people ignore them. They can be used for country codes (.co.uk or the like) or the type of site it is (.com commercial, .org non profit organization, etc.). The middle domain is whatever you want it to be. Then the subdomain is often used for organizing and breaking down a site. Especially useful when different resources are on different servers but you want them under the same domain.

As mentioned before, the port is unnecessary unless you are using a nonstandard port. I've done this when testing different servers side by side and some may do this to obfuscate things for security (not very strong security) It can also be used to avoid blocked ports on firewalls and the like.

The file path may not actually be a file path. Servers can implement rewrite rules to change the behavior. Careful observation should reveal if rewrite rules are used.

The actual file need not be shown, as servers can set what file name to default to if no name is present. Rewrite rules can also change this. Extensions don't need to reflect the actual file type as well, it depends on how the server is set up.

Query strings are not always apparent when rewrite rules are used. The premise behind the query string is to send plain old GET data. This is kind of like sending form data, only visible so people can link to things with information already entered. This is generally where you want to look for security holes.

Finally we have the anchor. This can be whatever information you want, but more often than not, it simply leads to an anchor on the page to scroll it to where you need.

All of these values can be modified. Let's say you go to a site and are trying to buy something. The URI looks like this.

http://www.insecurebuy.com/buystuff.php?item=expensiveComputer&price=10000

Well, there's something interesting. Maybe we can modify the price and get the expensive computer for free? While most things won't be that straight forward, learning to modify the URI can lead you to find hidden treasures, security holes or simply alter the appearance of some sites to fool people. However you look at it, modifying the URI is a good place to start in exploring a site and learning how it works and possibly how to manipulate it.

Tuesday, August 19, 2014

Web Hacking 101: View Source

There are a few hacking/security sites out there that let you go through challenges to learn. I'm just making posts off of them to refresh my memory because I haven't looked at this stuff in a while. This is square one.

To view the source on a web browser, you simply go to the site, right click on the page and select "View Source" or "View Page Source" on that menu. Most often, the keyboard shortcut to this is Ctrl+U.

The source you are seeing is just the HTML, maybe some CSS and JavaScript. Maybe a few other things depending on the site.

The value in this is because a lot of web software leaves comments to help designers and developers figure things out, and this can give anyone some insight into things going on behind the scenes. This particular source is static and from the start of when the page loaded. To view the dynamic source, DOM inspectors can be used and are pretty much default for major browsers. I personally prefer using the Firebug addon for Firefox because it's what I'm used to and it's easy to use.


Wednesday, July 30, 2014

Haskell Binary Serialization of Basic Math Data

I was reading up on some stuff and decided to try to do some things. The end result was a bit of research, long headache and obviously forgotten parentheses. Now despite Haskell's math appeal, it seems to lack a generic binary system to work with even though it supports octal and hexadecimal. This meant hunting down appropriate datatypes and binary modules that would cooperate together. This brought me to Data.Bits, which has all the generic binary operators and Data.Word for the Word8 datatype. The idea was to take some information, serialize it into binary and be able to unserialize it when needed. This would be easy enough, but I need to complicate things. Each piece of information only needs 4 bits, so I decided to cram 2 pieces of information on one byte.

So the first goal is to break down the data into some variables so I can be lazy, as well as have a point of reference. It was basically just to be a table of contents. That is of course, after the imports.

import Data.Bits
import Data.Word

zero    = 0 :: Word8
one     = 1 :: Word8
two     = 2 :: Word8
three   = 3 :: Word8
four    = 4 :: Word8
five    = 5 :: Word8
six     = 6 :: Word8
seven   = 7 :: Word8
eight   = 8 :: Word8
nine    = 9 :: Word8
plus    = 10:: Word8
minus   = 11:: Word8
times   = 12:: Word8
divide  = 13:: Word8
ignore  = 15:: Word88

Easy enough, simple math info. The ignore piece is just to have a filler should something accidentally slip into the stream. Okay, now that that is all out of the way, it's time to look at serializing a String.

serialize :: String -> [Word8]

serialize [] =
    []

serialize (x:y:xs) =
    sHelper y ((sHelper x 0) `shiftL` 4) : serialize xs

serialize [x] =
    sHelper x 0 `shiftL` 4 : []

sHelper :: Char -> Word8 -> Word8

sHelper c i
    | c == '0' = i
    | c == '1' = i .|. one
    | c == '2' = i .|. two
    | c == '3' = i .|. three
    | c == '4' = i .|. four
    | c == '5' = i .|. five
    | c == '6' = i .|. six
    | c == '7' = i .|. seven
    | c == '8' = i .|. eight
    | c == '9' = i .|. nine
    | c == '+' = i .|. plus
    | c == '-' = i .|. minus
    | c == '*' = i .|. times
    | c == '/' = i .|. divide
    | otherwise= i .|. ignore

The serialize function is to break down the information to be consumed by the helper function. The first character goes to the helper, which takes a Word8 that may or may not contain information. I did this because that seemed easiest, just pass a null byte. Since only 4 bits are used, I then shift the bits to the left for and OR some more information on. If there is an odd number of information, simply pad it with ones to be sure it's not mistaken for anything else (since all zeroes is a zero).

Now that we have that sorted, the next thing to do is reverse the process. Like the serialize function, the unserialize function will handle erroneous data simply by using a pound sign (#).

unserialize :: [Word8] -> String

unserialize [] =
    []

unserialize (x:xs) =
    usHelper (x `shiftR` 4) : usHelper x : unserialize xs

usHelper :: Word8 -> Char

usHelper i
    | test == divide = '/'
    | test == times  = '*'
    | test == minus  = '-'
    | test == plus   = '+'
    | test == nine   = '9'
    | test == eight  = '8'
    | test == seven  = '7'
    | test == six    = '6'
    | test == five   = '5'
    | test == four   = '4'
    | test == three  = '3'
    | test == two    = '2'
    | test == one    = '1'
    | test == zero   = '0'
    | otherwise      = '#'
    where
        test = i .&. ignore

Since we are only using 4 bits, I took the same approach of shifting the bits to work with them. Shifting aside, to extract the number  of bits we need, it's as simple as ANDing against all ones of the bits we wish to check, then comparing that to the expected value. This may be a bit more extravagant than it needs to be, but it works and it seems efficient enough (running in GHCi and serializing/unserializing 1000000 bytes).

Friday, June 27, 2014

Web Dev and Auditing Tools

I've been using Firefox for a while and I find it to have some of the best tools for web development and basic auditing. So I decided to make a collection of some of the tools I think are very useful. You can check it out here. Just to add some explanation, here's a quick breakdown and explanation of the tools and what you could potentially use them for.

Firebug - This tool is one of my favorites. There is a Javascript console to interact with web pages and inject code in. DOM inspection as easy as a right click. Viewing of CSS and quick editing for adding or removing properties. HTML editing. Network monitoring. Cookie viewing and editing. It's the most amazing web development tool.

NoScript - Not only is this a security tool, it allows you to enable or disable various pieces of Javascript and Flash on a web page. I've used it to see websites before Javascript dynamically alters them and that can be quite useful. Also gives some ways around those annoying Javascript validation checks.

Greasemonkey - A very robust tool to create user scripts. A user script will run when a web page loads, basically giving you an automatic way of injecting Javascript code. On top of that, there is quite a repository of useful tweaks and tools that you can add in. Lots of potential for what you can do with this one.

Tamper Data - Spoof headers. Plain, simple, easy. A great way to check for security holes, bugs or just have fun sending sites erroneous data.

Cookies Manager+ - View and edit cookies. Firebug can do this, but the interface here is a bit better for such tasks in my opinion.

Hackbar - A toolbar with some premade tools to aid in auditing and penetration testing. This won't hack a site for you, but it makes setting up a hack a little bit quicker and a lot easier. It requires some skill and knowledge to use but can give you some ideas of things to look into to learn as well.

RefControl - Spoof your referer. It will allow you to automate spoofing your referer.

User Agent Switcher - Tell a site you're a different browser, a made-up browser, look for security holes or whatever. This allows you to automatically spoof your User-Agent.

Saturday, May 10, 2014

Python 3 Strings and ctypes

I was playing around with ctypes on Python 3, when I noticed something weird. Attempting to pass a regular Python string, which from what I understand is a utf8 string, it just didn't work. Functions like printf or anything that took a string just didn't cooperate with it. After some reading, I found a solution. Unfortunately I don't know enough of the ins and outs to explain it, but it seems to only accept a byte string (b""). So it was easily fixed by passing the string with str.encode("utf8").

Friday, April 4, 2014

Maintaining Your Computer

More often than not, I find a lot of computers running slow despite being new or recently upgraded. Whether it be a Windows or Mac install, even came across a rather bogged down Ubuntu computer. The cause of such things tends to be a PEBCAK error (Problem exists between chair and keyboard; aka the user). The problems will get pushed so far that most just backup some data then do a fresh install, or upgrade some stuff, or even get a new system all together.

With any luck, I might be able to help you squeeze a little more time out of your system, possibly enough time to save up for a better upgrade when it really is time to do so. So let's take a look at some common problems that people cause to their own system.

One annoyance is "power users." People claiming to be power users like to overload their system with absolutely useless extras often displaying information that you don't need to know. For example, monitoring the CPU, memory, disk space, and temperature through graphic gauge widgets crammed on your desktop may look nice, but do you ever do anything with that information other than when trying to do things like benchmark or check to make sure your computer has what it needs? More often than not, that stuff is covered up or in the background being ignored by the user just wasting resources. I knew someone that claimed to use a CPU monitor constantly, but when asked why, there was no real answer. I use monitoring programs, but built in ones like task manager and system monitor, and that is only when trying to identify a problem or just to check on how everything is going. The main key is that these are periodic checks and there is little reason to get this information streamed in a GUI to you when most lighter weight tools would suffice and not add to the overhead.

Installing every tool, video player, addon, widget, etc. as possible is another problem I have seen. People install tools that half the time they don't even know what they are for or how to use them. Then they forget about all these little things and leave it there. Sometimes they do remember to uninstall, but never look for any left over files that can be left behind. I have gone through some long lists of programs that when I ask if the user needs or uses them, I get met with confusion as they don't even know what half the things do. Granted some programs like to install their own extras like toolbars which can cause this as well, however it's the stuff they obviously knew about that is the real annoyance. I'll also see multiple tools that do the same things, like video players. This occurs because they do things like download a codec the player they use can't read. So then they download a new video player, maybe a converter or two. Little do they know is that with a little research, they could add codec support to their player or get a single player that plays all the codecs they have.

People run too much shit at once. I try to avoid swearing in my blog, but I feel the need to swear to emphasize how stupid it is. I've seen browsers open with double digits of tabs. You can't look at all the tabs at once, learn to use bookmarks. Tabs are a convenience to switch quickly between pages and avoid reloading. If reloading the page doesn't matter, don't feel the need to keep it as a tab. Also, if you are not going to use a program for longer than it takes to close it down and start it back up, consider closing it. Don't waste resources on something you are not using unless it needs to stay open.

Getting upset and spamming key presses and mouse clicks. User input takes up resources. Adding more just increases the load, not to mention can launch actions not originally intended. Give it some time, sit there, shut up and let the computer get work done without the extra angst. All it does is add to the problem and upset yourself. I will often get up and do something else if whatever I'm doing is taking long enough. It's constructive and keeps me from getting a hammer and smashing the computer to bits, and believe me I've gone so far as to get a hammer out.

Restart the computer once in a while. Windows computers especially need to be restarted to clear out certain problems. Unix based computers like Linux and Mac don't always need to be restarted, but it shouldn't hurt anything to give it a chance to reload everything. I see people leave their computers, even laptops, on for days. Laptops especially were not designed to stay on forever. My server is on basically 24/7, but I still take time to update and restart it every so often.

People never seem to understand what cache is, so it builds up. Things can also hide in their on a Windows system. While temporary files are cleaned up by the OS, cache files are often at the discretion of the program using them. Most tools with caches have ways to limit the size allowed, however there are many tools built in to clean them out. On Windows, you can use a built in program called Disk Cleanup. I personally use CCleaner, which does a few other things I'll mention next. Mac and Linux can simply be manually cleaned, just google where to look as it is not guaranteed to be in the same place for any system.

A Windows specific problem is what is called the registry. The registry contains a lot of information that basically lets the OS know how things are configured. Restarting can help keep this tidy, as broken registry keys can cause problems. Sometimes this may not be enough. A tool like CCleaner has a registry cleaning tool to help fix up the registry. There is a chance it can break the system, but I personally have not had that happen.

So let's go through a basic list of how to keep your system maintained.
  • Don't overload your computer with pointless widgets you don't need (unless you really really want to, but keep it slimmed down)
  • Don't install tools you don't need or don't know what they do
  • Research what you need before you install every video player and converter just to watch your pirated shows
  • Don't run everything on your computer, only what you need when you actually need it, then close it down when you can and won't inconvenience yourself
  • Close the internet tabs, the internet is not going anywhere and I promise you it will still be there when you return (if it's really important, you can save it for offline reading *HINT *HINT)
  • Don't get upset and go clicking crazy on your computer when it is going slow, walk away and let it do its thing, computers may be fast but they don't work instantly
  • Relax
  • Restart once in a while and let the laptops rest and cool down
  • Caches take up space, clear it out once in a while
  • Try to use built-in tools instead of installing new stuff that does the same thing, the built in ones often work really well
For Windows, a program like CCleaner can also be helpful. It can clear the cache even with secure deletion options (we all know you're paranoid enough to want this). It can also fix some registry problems. It can even securely wipe blank disk space. I personally install it on every Windows computer and it more often than not will help get rid of some pesky small problems.

Now this is not a complete list of everything that can be done, but by remembering these pointers on a fresh install, you have the potential to keep your computer going strong for longer than most might think. My laptop is over six years old as of writing this and has outlived quite a few computers newer than it. The only problem it had was a faulty motherboard (got fixed and caused the network card to need replacement). Oh, and the webcam doesn't like to cooperate, but I believe that's due to the cable being in a hinge.

In conclusion, it is my findings that the reason computers often run slow or have problems is the result of something the user has done or is doing. Not always the case, but when fixing someone's computer, that is the general idea I start with when looking for the problem. These tips are just general thoughts on how to work on a computer and run with few resources, they are not guaranteeing anything. So if doing all of this still does not help, then maybe it's time to upgrade, especially if you're a gamer.

Tuesday, February 18, 2014

Haskell GTK Example (Hello, world!)

I quite enjoy using Haskell, but from my own attempt, anything involving monads has proven to be quite nightmare-ish. Since it had been a while since I've played around in Haskell, I decided to look into something I had been reluctant to since I started, graphics. Upon looking at an example I thought would be simple, I found myself intimidated and flooded with stuff that I had no idea what it did. So I decided to find a hello world example, then rewrite it in a more readable fashion, at least in my opinion.

import Graphics.UI.Gtk

main :: IO ()
main =
    -- Start the graphics
    initGUI >>
    -- Create a new window object and do stuff
    windowNew >>= (\ window ->
        -- Quit when the window is gone
        onDestroy window mainQuit >>
        -- Set some window attributes
        set window [ containerBorderWidth := 10, windowTitle := "Hello, world!" ] >>
        -- So it has a decent size
        windowSetDefaultSize window 200 100 >>
        -- Now let's make a button
        buttonNew >>= (\ button ->
            set button [ buttonLabel := "Hello!" ] >>
            -- Multiple events can be assigned, they run in order
            onClicked button (widgetDestroy window) >>
            -- Put the button on the window
            set window [ containerChild := button ]) >>
        -- Display the window and contents
        widgetShowAll window) >>
    -- Actually run the graphics
    mainGUI

I chose to avoid ado notation because in the examples it looked sloppy and unreadable. Instead I used lambda functions along side monad sequencing functions (>> and  >>=). This has allowed me to explicitly separate the window setup and even the button setup in an attempt to avoid a procedural style with variable assignment.

It makes a window, the button makes it exit. Simple and clean.

Sunday, January 19, 2014

Bulk File Renaming

While in the process of transferring music and shows to a media server, I noticed an annoying problem. All the file names were formatted differently than I wanted. After manually changing files in one folder and realizing how long it took, I thought there must be an easier way. After a very short Google search, I figured what a better way to support what I need than to make such a program myself. So I created rename.py. It is a command line utility that allows bulk renaming of files and/or directories, supporting basic stripping, regular expression matching and Python string formatting.

You can find the download link for it here.

Now here is a quick rundown on ways to use it.

#strips first 4 chars off every file
./rename.py 4
#strips in the Music/5FDP folder
./rename.py -p Music/5FDP 4
# Takes any file in Music/RATM that looks like "something - somethingelse"
# and changes it to RATM.somethingelse
./rename.py -p Music/RATM -r ".+ - (.*)" "RATM.{0}"
# help for more info
./rename.py -h

There are other options like -d for including directories and -o for only directories. Named groupings are also supported, for more information, it would be best to look into regular expressions and Python's str.format() to fully utilize this tool.

Thursday, January 16, 2014

Laziness and Non-Strict Programming

I found myself buried in some PHP code recently with completely redoing my site. On top of that, I was also patching another site who had switched to some new software. On the new software I was patching, the error logs were massive, but from the front end everything seemed all right. A lot of errors emerged from pure laziness causing inconsistencies and I resorted to very messy quick fixes due to a lacking desire to read and edit everything.

A non-strict program will allow the use of variables that have not been declared, either giving a warning or silently ignoring with an error and continuing on. The biggest problem these cause is when doing conditional testing. In a language like C, everything must be declared, even if it is not used when it runs, any reference means it needs to be declared. In other languages, it may result in a warning or some may ignore it all together if it is never used.

In most interpreted languages, an if statement takes on a bit of lazy behavior, in that if a condition isn't needed to finish, it isn't evaluated. For example, the statement $a = true; if ($a || $b);, the variable $b will not be needed as regardless of its value, the end result will be true. Because of this, nothing will happen with $b unless $a is false. So unless every possible condition is tested, an error or inconsistency could be lurking in the shadows. Due to this, an undeclared variable used to result in a False, 0 or empty string, depending on what it is being used for. However, with a strict behavior, this is not the case.

Languages like Perl and Javascript >=5, have an option to use strict semantics. The end result is either the code adheres to strict standards or it fails all together, as apposed to silently shirking it and continuing. PHP can also enable strict standards, but the bottom line is that all it will do is corner the programmer.

Regardless of a strict mode or not, a programmer should always try to declare all variables correctly and not rely on fall-backs to pick up any oversights. A programmer should also understand that just because a program appears to work, does not mean it is actually working correctly. One thing I find a double-edged sword in PHP is the isset() function. While it makes for easy patching, it also means down the road it could lead to bulkier code always checking if a variable is set or difficult to decipher code when trying to find where a variable is actually declared, and why.

Now before someone jumps on the bandwagon of something like being "Pythonic", you can actually easily emulate an isset function, or set up a try/catch structure to silently ignore such things.

def isset(a):
    return a in globals()

This is just a rough version, pass the variable as a string and it will check for a global variable declared with that name. It can be altered to check further, just avoid getting stuck in a looping reference. The same can be done in other interpreted languages where such a structure is visible.

There are always ways to be lazy or make programming seem non-strict, but the bottom line is that the large-scale effort and the complications are not worth the possible benefits, whatever people may see in it.

The main reason I can see people finding a use for it is in user input. User input and IO tasks in functional programming languages are considered unreliable and with side effects, and I agree. For this reason, I feel that a proper way to deal with it is assuming Murphy's Law.

Tag Cloud

.NET (1) A+ (1) addon (6) Android (3) anonymous functions (5) application (9) arduino (1) artificial intelligence (2) bash (3) c (7) camera (1) certifications (1) cobol (1) comptia (2) computing (2) css (2) customize (15) encryption (2) error (15) exploit (13) ftp (2) gadget (2) games (2) Gtk (1) GUI (5) hardware (6) haskell (15) help (5) HTML (4) irc (1) java (5) javascript (20) Linux (18) Mac (4) malware (1) math (8) network (5) objects (2) OCaml (1) perl (4) php (8) plugin (6) programming (42) python (24) radio (1) regex (3) security (21) sound (1) speakers (1) ssh (1) telnet (1) tools (11) troubleshooting (1) Ubuntu (3) Unix (4) virtualization (1) web design (14) Windows (6) wx (2)