Monday, December 27, 2010

Securing the Redmine_S3 plugin

We run redmine internally here at Fuery Solutions. Redmine is a fantastic tool for managing software development projects.

One of the unfortunate "features" redmine has is the habit of storing uploaded files without any security, regardless of whether the system itself is password protected or not. The redmine s3 plugin echoes this habit, setting all uploaded documents to readable by the entire internet. Obviously, the URLs are somewhat obscure, but as the cliche goes, obscurity is not security.

Here are instructions for altering the plugin to use temporary authorized URLs. This effectively offloads the security requirements to Amazon's formidable infrastructure.

These instructions apply to:

  • Redmine 1.0.x
  • Redmine_S3 v 0.03
Files you'll be editing (where "redmine" is your rails application root):
  1. redmine/vendor/plugins/redmine_s3/lib/redmine_s3/attachment_patch.rb
  2. redmine/vendor/plugins/redmine_s3/lib/redmine_s3/attachments_controller_patch.rb
  3. redmine/vendor/plugins/redmine_s3/lib/redmine_s3/connection.rb
First, we need to disable the "set newly uploaded files to be readable" command. This entails commenting a single line in attachment_patch.rb, on line 24:

#Private (not readable by everyone) is the default.

This handles newly created files. Next, we need to add the capability to retrieve a URI with the AWS temporary authorization keys. The S3 lib the plugin uses actually contains theses goodies already, so we just need a wrapper function in connection.rb that uses the QueryStringAuthGenerator class. This function isn't as clean as it could be, but we threw this together in an hour. Add this function to the Connection class in connection.rb:

def self.private_uri(filepath)
 load_options unless @@access_key_id && @@secret_acces_key
 @@qs_conn =, @@secret_acces_key, false) unless @@qs_conn
 @@qs_conn.get(bucket, filepath)

I added this on line 37, between the bucket and uri functions. You'll also, of course, need to initialize @@qs_conn by adding this at the beginning of the file (line 7 or so):

@@qs_conn = nil

Finally, we need to adjust the controller function that handles the response to the attachment GET requests themselves. Adjust attachments_controller_path.rb on line 23:

#Comment the current line 23.
#New code

Don't forget to restart your application after performing these changes. You'll also, of course, need to adjust the file settings in AWS for previously uploaded files. Although this new code works for viewing those files, the security settings ("visible to everyone") need to be reset manually.

Tuesday, November 2, 2010

At a Glance To-do List for Running Rails 2 and Rails 3 on the Same Linux Server

This is geeky. You've been warned.

Environment: Rails 2.3.5 app - redmine,our internal project management tool, in our case - running on Ubuntu 10.04.
Requirement: Install a Rails 3 app - our new corp web site in this case. Goodbye, Wordpress, hello home-grown RoR happiness.

Note: this will down your rails 2.3.5 app briefly.

  1. Make sure your core libs are up to date:
    1.  apt-get install libyaml-ruby
    2.  apt-get install libzlib-ruby
  2. Update rubygems. Ubuntu won't let you using "gem install rubygems", so do this instead:
    1. gem install rubygems-update
    2. rubygems-update
  3. Install bundler
    1. gem install bundler
  4. Install Rails 3. This will take a few minutes.
    1. gem install rails
  5. Go to your Rails 3 app directory and run:
    1. bundle install
  6. Reload apache (optional)
    1. /etc/init.d/apache2 reload OR service apache2 reload
  7. Your old Rails 2 app will now be down and your new Rails 3 app is running. Now we reinstall Rails 2. Bundler lets these coexist peacefully:
    1. gem install rails -v=2.3.5
  8. Reload apache. 
    1. /etc/init.d/apache2 reload OR service apache2 reload
Check your work by accessing both of your applications. Voila!

Monday, May 24, 2010

Migrating and Cracking Tritek Legal Case Management

In my development of the MerusCase module that does a data migration from Tritek to MerusCase, I have thoroughly decoded their database schema.  What a mess!  I had to develop contact 'de-duping' software using what we call 'fuzzy matching' via a Levenshtein metric.  That was really intriguing to develop.

However, in order to properly map data from their system to ours, I needed a working copy of the software to reference from and see how that data was being stored in their archaic dBase (Microsoft FoxPro) format. It's funny that Microsoft has officially announced the death of FoxPro, i.e. they have announced the dates after which they will no longer support the product.  It's even funnier that if Tritek has any chance of keeping up with technology they will have to start their app from scratch.  Anyone who as ever used the program realizes how shoddy the user interface is -- irritating to navigate, an eyesore to look at (no taste for aesthetics whatsoever!), and a counter-intuitive approach to UI design.

Apparently Tritek's tampering check is easy to crack.  First off, if you rename the xmgmt.exe file with a .txt extension and open it up in TextPad, you'll see that all the FoxPro code is embedded in plain text.  That is, you can see exactly what the developers wrote that make the application run and do what it does.  If you do a search for 'tampered' or 'exempt' you will find the dialog box that tells you to buy a license, and you will also find the code that does the security check.

All it does is do a 'dir x: > WORK\vsno.txt' on the drive that your data sits on, saves the output into the WORK folder, looks for 'Volume Serial Number' in that text file, because it grabs the 9-char s/n for your drive.  It then hashes it and computes the corresponding 8 to 11 digit integer using a built-in FoxPro hash function (SYS 2007).  That integer is compared to the value contained in serno.dbf file, located in your data folder.  There are 'backdoors' aka Tritek Maintenance logins hard-coded too (see code snippet below).  I could run a brute force attack on those codes using a utility like MDCrack to find out the universal volume-s/n they use...

Fortunately, there is a simple command-line utility that allows you to change your drive's serial number.  This has no effect to anything else, so far as I can think of.  Nothing uses HDD serial numbers except for the occasional 15-year old p.o.s. software (Tritek for one!).  Download volumeid.exe from Microsoft Technet (it's free) or from here.  It's usage is simple: volumeid <driveletter:> xxxx-xxxx.  You'll have to reboot for changes to take effect.

Maybe if I have time in the future, I'll throw together a little script that will disable or patch tritek to completely bypass security checks altogether.  In the world of cracking, a bypass may be as simple as converting a machine code instruction 'jump if equal (je)' to 'jump if not equal (jne)'.  =)

a="dir "+xdata+" >"+xwork+"\vsno.txt"
RUN &a
c="Volume Serial Number is "
SELECT serno
    IF (b="446519453" .or. b="487413866" .or. b="1505040575" .or. ;
    b="3629040784" .or. b="659246687" .or. b="140427344" .or. ;
*!*        IF (b="446519453" .or. b="487413866" .or. b="1505040575" .or. ;
*!*        b="3629040784" .or. b="659246687")

Wednesday, April 7, 2010

How to Record Help Videos Using Open Source Tools and Youtube

We've just begin using this method for recording How-To videos for the MerusCase Knowledge Base. It's a little involved, but sometimes nothing works better than "show me how".

  1. Download and install CamStudio, open source Screen Recording software. 
  2. Most of us here use a dual-monitor setup. This is an ideal situation because you can record one entire screen. Set your screen resolution to a video-friendlier size, like 800x600. You'll also need to set your primary monitor to the screen that you want to record.
  3. In CamStudio, set the "Region" to "Full Screen". I also like to set the View to "Buttons View" in case the CamStudio control panel ends up in a portion of your video.
  4. Sanitize your desktop and whatever you'll be recording. That means the profanely named files on your desktop will have to be stowed somewhere else for now. Close extraneous applications, too.
  5. Record your video. Don't worry about mistakes, just get good footage.
  6. Download VirtualDub. "Install" this by downloading and extracting the zip file. Run auxsetup.exe to perform some basic setup. Then create a shortcut for "VirtualDub.exe" and place it somewhere convenient. 
  7. You'll need an MP4 encoder if you want to finish uploading to YouTube before strange hair starts growing out of your ears. You may already have one -- the Windows DLL required is mpg4c32.dll. I had a hard time naviagating the Windows Media download site at Microsoft's site, but I found what I needed by running the installer at
  8. Open the video file generated during your CamStudio session.
  9. Use VirtualDub to delete sections of the video as needed. "Set selection start" and "Set selection end" under the edit menu are your friends here.
  10. Set your compression to mpeg 4 in Video->Video Compression.
  11. File -> Save As AVI to finish up.

Friday, April 2, 2010

Basing the Business on Cloud Computing

Sometime in late 2008, the team here at Fuery Solutions made the decision to base the future of our business on software-as-a-service products targeted at legal professionals.

MerusCase, the first of what may become a suite of products, is focused on Workers Compensation attorenys in California. For a variety of reasons, MerusCase is a web-based, "software as a service" (SaaS) application running entirely on the infrastructure provided by Amazon Web Services. Our salespeople and partners like to refer to this as "operating in the cloud" because the concept of "cloud computing" is mentioned every 12 seconds on MSNBC these days.

That's all true, and indeed, my recent post on practicing what we preach with regard to moving our own infrastructure, data, and operations to web-based services (the "cloud") echoes this online-centric paradigm. (I should note, with all due respect, this is quite a bit harder for us as developers and data crunchers -- we have to deal with a wide variety of platforms, disparate customer data, and other such hassles. It would be such a relief to have to worry only about Word Docs, PDFs, and email! :-)

In reality, MerusCase is a software product sold as a service (SaaS again) that leverages the cloud computing infrastructure offered by Amazon Web Services. Fuery Solutions is therefore not a "cloud computing" provider per se; we're merely building and selling a product that happens to "run in the cloud".

One of the objections I've run into here and there in the sales process is "security". I've placed the term in quotes because often the word is used to encompass a wide variety of opinions, many of which are based more in emotion than in technical concern. What my future customers are really bringing up is the feeling that they may lose control of their data. There is comfort for a great many folks in seeing a black box in the corner that (hopefully) contains all of their data. In response, I usually point out the following:
  • MerusCase has to stand up to the internet. That means I'm thinking about crazy Ph.D. hackers in Russia who live on four bucks a day and have a bone to pick. Your little Windows 2003 server in the poorly ventilated closet adjacent to your office has to contend with your ex-wife and that receptionist you canned six months ago. Suffice it to say that your security model can be one of obfuscation -- your server is secure because no one knows it is there. MerusCase is secure because it uses published and proven security models. (The end-to-end communication is 128-bit SSL encoded, like your online banking system, and sensitive data in the database is encoded using unique data from your firm meta information, subsequently 256-bit SHA_1 hashed with said dynamic key, different for every single client, and stored in a database that is only accessible from the MerusCase web server infrastructure. We built the damn thing and schmoozing you into giving me your password would be easier than trying to crack that mess). If you trust your credit card with Amazon, you can trust your data with MerusCase. Security is not based on luck or lack of knowledge; true security is telling criminals exactly how your lock works and knowing it is not worth the effort to attempt a breach.
  • Downtime of your local server is absolutely, without a doubt, higher than MerusCase. Those two days last June when you had to wait for your IT fellow to arrive, run to Best Buy, and install an new drive in your server, then restore your data imperfectly from backups? It might not be top of mind, but it happened. And if it didn't, you were lucky. 2010 may not be so fortunate a year. In contrast, data in MerusCase might be compromised in the event of a nuclear war. Companies a lot bigger than Fuery Solutions are running hundreds of millions of transactions per day on the same infrastructure. Now, would you rather trust the single hard drive platter in your little black box, or would you rather take advantage of the 40,000 servers (in October 2009) that make up the Amazon "cloud"?
  • Worries about the internet connection in your office are easily mitigated. A secondary internet connection for redundancy will cost less than the annual maintenance fee on your Windows Server license.
  • The benefits outweigh the costs. Yes, there are concerns because you can't hold the backup tapes in your hand. There is a certain comfort in the tangible, physical qualities of owning your own server. But How Much is your Fear Worth? "[Cloud Computing] presents real security issues, real security opportunities, and red herrings. In most cases the red herrings rule the day... [and after real world number crunching,] the system in the cloud is orders of magnitude less expensive than the other options."
  • Amazon has spent billions of dollars on their infrastructure. They've paid for a world-class outfit, and they have one. That's why Fuery Solutions and hundreds of other companies have chosen to base their businesses on this technology infrastructure. Why not leverage that investment?
  • Leveraging the web as a development platform allows us to bring more services to market faster. MerusCase has been updated almost 50 times since it's 1.0 release almost a year ago. Since then, we've added features like batch scanning, integration with Google Maps, synchronization with Google Calendar (and by extension Blackberry, Outlook, and iPhone), and chat-based support. We've backed up the application and data in a directed fashion 500 times and backed it up via automatic snapshot somewhere around 20,000 times. We routinely talk to external web-based services, leverage existing free software, and connect disparate data sources dynamically because we're on the web. We  run on iPhone, Droid, and the Mac. We can connect you with your clients and each other more effectively because communication and collaboration are what the internet was built for; it's not an afterthought strapped onto quaint software based on client/server technology developed back when going online meant a Prodigy account.   
Other Resources of Note

Thursday, February 4, 2010

MooTools Users: Implement a Hash.sort method

I notice that Firefox seems to maintain the order of key:value pairs in objects when iterating over them, while Safari and Chrome seem to sort the object internally (within their respective JS engines).  I  noticed this especially when making select elements.  I store the options as an object, then when drawing the page, I iterate over that  object making option elements. 
For example, I am making a select box that lists users  alphabetically.  Users are identified in the database by an id: 

var foo = new Element('select').inject($$('body')[0]); 
var options = {5082:'User A', 5085:'User B', 5074:'User C'} 
  new Element('option', {text:name, value:id}).inject(foo); 

In Firefox the select box would present users in order: A,B,C, but in the others, users would appear in order by id: C,A,B.  A neat function  for tackling this sort of problem would be Hash.sort. 
        Function: Hash.sort 
                Takes {c:0, a:1, b:2} and returns [{a:1},{b:2},{c:0}] 
        var out = [], 
                keysToSort = this.getKeys(), 
                m = this.getLength(); 
        (typeof fn == 'function') ? keysToSort.sort(fn) : keysToSort.sort(); 
        for (var i=0; i<m; i++){ 
                var o = {}; 
                o[keysToSort[i]] = this[keysToSort[i]]; 
        return out; 



Results In: 

[Object { a=1}, Object { b=4}, Object { c=3}, Object { z=2}] 

Then our select box routine becomes: 

var foo = new Element('select').inject($$('body')[0]); 
var options = {5082:'User A', 5085:'User B', 5074:'User C'} 
  $each(el,function(name, id){ 
    new Element('option', {text:name, value:id}).inject(foo); 

Ruby programmers may recognize this method ( 

Monday, January 18, 2010

Chomp your PHP for good health.

We had some weird problems in testing one of our applications today. It turned out to be a newline after a ?> tag in a core config php file, so anything being outputted was preceded by a newline. Normally this isn't much of a problem--web browsers don't care that much about whitespace. Pickier clients, however, got thrown off and would complain about data being corrupt.

Friday, January 8, 2010

Where Tritek Case Management Stores Passwords and Login Information

In order to move Tritek users over to MerusCase, the superior case management system, one of my projects has been to reverse engineer and write a migration system for Tritek.

If you have lost your password or simply would like to hack into Tritek or impersonate someone else, it is easy to find the passwords and logins in plain text in the DATA/ folder that Tritek uses.

First, if you don't know where to find where Tritek is storing its data tables, open up the executable SETUP1.exe in the XMGMT/ folder. Alternatively, open up DATA/parms.dbf with a DBF (dBASE) viewer (For example DBFView or DBFViewer 2000) -- there is a 'data' column that specifies a file path to your data.

Now, open up DATA/logins.dbf with your dbf viewer and there are columns for name, password, login dates, and so on. They are all stored in plain text so you won't have to do any password hashing or such.

Word 2007: How to enable editing on a read-only protected template

1. Rename word .docx file to .zip.  Unzip with your favorite zip program.
2. Open file (archive)/word/settings.xml in text editor.
3. Change property w:enforcement from "1" to "0" within node that reads something like this:

<w:documentProtection w:edit="forms" w:enforcement="0" w:cryptProviderType="rsaFull" w:cryptAlgorithmClass="hash" w:cryptAlgorithmType="typeAny" w:cryptAlgorithmSid="4" w:cryptSpinCount="100000" w:hash="KyPJG/+vxA4Let1njKgfCpSvJNc=" w:salt="dDf7X+CaLHLXe/H/1zZMqQ=="/>

4. Save and close file.
5. Rezip into another archive and rename file with .docx extension.