Wednesday, December 11, 2013

BrowsePass as a Chrome app

I am pleased to announce the availability of BrowsePass Chrome app.

This is an easier way to set BrowsePass up on the Google Chrome browser (as well as its open source cousin Chromium). The Chrome app alleviates the most cumbersome steps in setting up BrowsePass: finding a web host for the source code. Everything else remains the same, including the convenience of opening your password database with a browser.

Though there is not yet extension/add-on/app for other browsers (such as Firefox, Safari, Opera), they can still run BrowsePass normally.

As usual, the source code (including the Chrome app) is at BitBucket.

Tuesday, December 10, 2013

Chainload from GRUB to Chameleon boot loader

A quick note to myself. Assuming OS X is installed in the 2nd partition of the 1st hard disk, modify your /etc/grub.d/40_custom file to have:

menuentry "OS X" {
    insmod hfsplus
    set root="(hd0,gpt2)"
    chainload /usr/standalone/i386/boot0

Then remember to run update-grub2.

The file /usr/standalone/i386/boot0 can be found in your hackintosh. It is the boot code from Chameleon. If you do not find this file, grab it from Chameleon package.

Wednesday, November 27, 2013

Language definition file vietnam.ldf not found

Just a quick note to myself. VnTeX recently moved its vietnam.ldf file to babel's contrib as vietnamese.dtx. The move happened on April 14, 2013. The babel package in MiKTeX is currently at March 23, 2013. The vntex package in MiKTeX is currently at May 21, 2013. That is to say vntex package no longer provides vietnam.ldf, yet babel package is still not update-to-date enough to have vietnamese.dtx.

The fix is to maintain your own vietnam.ldf file. The code (that was taken before the move) is pasted below.

% Copyright 2000-2005 Werner Lemberg .
% This file is part of vntex.  License: LPPL, version 1.3 or newer,
% according to
% vietnam.ldf
% written by Werner LEMBERG 
% History
%   1.0  2000/09/01
%     First version.
%   1.1  2001/05/26
%     Moved \endlinechar downwards.
%   post 1.1  ?
%     Don't check for dblaccnt.sty.
%     Add support for ucs.sty.
%     Don't define \captionsvietnam but load vncaps.tex.
%   1.2  2005/04/21
%     Add copyright message.
%     Minor clean-ups.

    [2005/04/21 v1.2 Vietnamese support from the babel system]


\ifx\l@vietnam \@undefined
  \adddialect\l@vietnam 0


  {\message{Loading definitions for the Vietnamese font encoding}}
  {\errhelp{I can't find the file `t5enc.def' for Vietnamese fonts}
   \errmessage{Since I do not know what the T5 encoding means^^J
               I can't typeset Vietnamese.^^J
               I stop here, while you get a suitable `t5enc.def' file}

  {\PackageWarning{babel}{No input encoding specified for Vietnamese}}

\endlinechar \m@ne

  \ifx \UnicodeCharFilter \@undefined
%   \UCSProtectionUnichar

\let\viet \viettext





\endlinechar `\^^M


% end of vietnam.ldf

Sunday, September 15, 2013

Introducing BrowsePass, a KeePass on the web

Update: Because MyDrive does not serve CSS files as text/css and most browsers block such stylesheets, you may find very disturbing render of the web page as reported in issue #40 ( Please use the Chrome app, or another hosting provider.

Update: There is now a Chrome app. If you use the app, you do not need to carry out steps 5 to 7 below.

Update: Please file bugs and feature requests at the project's page.

This post was initially intended to be named "How to have your own open source XXX" where XXX is your favorite commercial online password manager. Then I realized that would have been too deceiving because I don't know jack about them. I have never used them. How can you trust a closed source password management software?

In contrast, BrowsePass is a GPL licensed JavaScript application (and library) to open KeePass password databases in (modern) browsers. It is great when you're on the move and don't bring KeePass with you or cannot install it on your machine but you need to access a password in your vault.

Setting up BrowsePass is as easy as uploading all the files to your web hosting provider. I would recommend you to use MyDrive because it offers WebDAV, and serves files with sane MIME type instead of forcing you to download them. You can use MyDrive as your HTTPS web host, as well as the remote storage for KeePass.

BrowsePass can read a dropped in local database file as well as a remote database file. In the second case, cross origin policy might prevent the loading of remote file, unless the remote server has enabled Cross Origin Resource Sharing (CORS).

In summary, here're the steps to set BrowsePass up for read, with KeePass for write.

  1. Register an account with MyDrive.
  2. Create a database with KeePass.
  3. Upload your database to MyDrive. Let's say you have uploaded it as personal.kdbx.
  4. In KeePass, open URL From now on, whenever you save, your file on MyDrive will be updated.
  5. Download latest version of BrowsePass.
  6. Unpack and upload all the files to MyDrive.
  7. Browse to
  8. You can either drag and drop a local KeePass database file to the second box, or type in an URL to your database in the first box. The URL can be either relative such as personal.kdbx or an absolute one such as

Here are some mandatory screenshots. I hope you'll like it.

How to read .NET GZipStream with Python zlib

Just a quick post, sort of a note to myself. The code below can be used to inflate (unzip, decompress) the byte string that was created by .NET GZipStream.

import zlib
data = 'abcdef' # get the input bytestring
data = [10 : ]  # skip the first 10 bytes, .gz file header
decompressed_data = zlib.decompress(data, -zlib.MAX_WBITS)

Saturday, August 10, 2013

Install Debian on an emulated ARM machine in Mac OS and Windows

A quick post with some commands to create a running ARM machine in your hackintosh or Windows.

  1. Install QEMU.
    • On Mac:
      1. You need Homebrew. If you do not have it, stop everything and go install it.
      2. Then install QEMU.
        brew install qemu
    • On Windows: Download and install the prebuilt QEMU.
  2. Download a pre-built ARM kernel and init ramdisk from Debian.
    wget --continue
    wget --continue
  3. Create a raw disk image for your virtual machine.
    qemu-img create -f raw hda.img 2G
  4. Launch the virtual machine and finish installation. You will see a no-boot-loader warning near the end. Do not worry about it. When the machine reboots, you can safely terminate QEMU.
    qemu-system-arm -M versatilepb -kernel vmlinuz-3.2.0-4-versatile -initrd initrd.gz -m 256 -hda hda.img
  5. Extract the newly installed kernel and init image.
    • On Mac:
      1. Install ext4fuse. Remember to copy the kernel extension (kext) to the right place and chmod it properly.
        brew install ext4fuse
      2. Mount the disk image to extract the installed kernel and init ramdisk.
        hdiutil attach -noverify -nomount hda.img
        # take note of the device name
        mkdir tmp_mnt
        ext4fuse <device> tmp_mnt
        cp tmp_mnt/boot/initrd* tmp_mnt/boot/vmlinuz* .
        umount tmp_mnt
        rm -rf tmp_mnt
        hdiutil detach <device>
    • On Windows: Use Ext2Read to mount hda.img and extract the files from /boot.
  6. Launch the virtual machine again with the new kernel and init ramdisk. Notice that you need to replace the kernel and init ramdisk in the below command with what you copied in the above command.
    qemu-system-arm -M versatilepb -kernel vmlinuz... -initrd initrd... -m 256 -hda hda.img -append "root=/dev/sda1"

Wednesday, August 7, 2013

Notes about DEFCON 21 CTF

Last week was DEFCON 21, one of the many conferences I'd been saving up for. I was fortunate to play in the Capture the Flag game this year with team CLGT. I like the design of the game, so I'm jotting down here a few notes about that.

  1. This is a zero sum game. There is a fixed amount of points in the game. These points change hand but they are not produced, nor consumed. When one team earns points, some other team must lose points.
  2. Defense is at least as important as offense. Gained points may be taken away quickly due to failure in maintaining a required service level agreement (SLA), and breach of security.

As an analogy, each team is given a patchy water tank filled with some water. The amount of water in the tank is your points. Your goal is to steal water from other teams. If the patch on your tank is broken, the water runs out. Therefore, it is extremely important to properly fix the tank up. Even if you have only one unfixed hole, water still runs out quickly.

Unlike other CTFs, DEFCON 21 CTF placed great emphasis on the blue side of the coin. I like that. It feels more wholesome.

By the way, if you're wondering how we did, the answer is our water ran dry ;).

Tuesday, August 6, 2013

Samsung, Apple, and Protectionism

In June, the ITC handed Samsung an import ban on some old Apple's products which violate Samsung's patents.

Then came the presidential veto of ITC's determination, overruling the exclusion order and cease and desist order. I have to emphasize that the US Trade Representative did not veto ITC's finding that Apple had violated Samsung's patents.

The question is if this is an example of protectionism in a free market economy.

If the ban is vetoed, what can the ITC award to Samsung in lieu? If there's no remedy for Samsung, and no punishment for Apple, has the whole thing been a huge waste of time and money?

Who is going to appeal to the higher Courts?

I welcome the US Trade Representative's veto because it protects consumer's interest. At the same time, the veto brings with it many more unanswered questions. This might signal the beginning of some rework in the US intellectual property system.

Tuesday, July 9, 2013

Rotate external display in Mountain Lion

At work, I have an external LCD monitor connected to a MacBook Pro running Mac OS X 10.7. The LCD monitor is vertically oriented so that I can read more on it.

I could not find any option to rotate this second display initially. I tried all the tips I could find but none allowed me to rotate the external display. People said you'd see a rotation option if you hold Command-Option and click on System Preferences, then click on Display (while still holding Command-Option). It was true. And it was only for your MacBook's built-in LCD display.

Turned out all I needed to do was to restart the laptop. The rotation option displayed itself after that. Perhaps there is some monitor capability discovery handshake that is only done at boot.

Saturday, June 22, 2013

Full disclosure versus Selective disclosure

Bloomberg recently reported that Microsoft "provides intelligence agencies (NSA, CIA, FBI) with information about bugs in its popular software before it publicly releases a fix."

Though I cannot confirm if other governments in the world were also alerted of the bugs or only the US agencies, this strongly smells like a selective disclosure practice that Microsoft is following.

Not only is it unfair, but it is also dangerous. For one, other governments are denied the early alert even though they pay the same price for Microsoft applications. Secondly, and more importantly, selective disclosure alienates those governments and foreign security researchers. Reporting a vulnerability to Microsoft earns the researcher maximum of $150,000 dollars (at Microsoft's discretion) and ironically puts his own country in an uneasy situation.

Some will argue that it's fair because there is a payout after all. They have entirely missed the point. Security is about trust. When a researcher reports a vulnerability to Microsoft, there is an implicit trust that that information is private. On one hand, Microsoft would expect the researcher to hold on the disclosure. On the other hand, Microsoft breaks that trust itself by letting some third parties know about the discovery. And Microsoft also breaks the trust between itself and its customers, causes dire political consequences.

Furthermore, there are adverse effects selective disclosure may have on the exploit market. Selective disclosure can only reduce the number of public bugs and hike up the price of vulnerabilities. Microsoft will become a victim of its own action when it has to spend more and more to acquire the information that it could have been given for free. All simply because there is no more trust.

I cannot tell whether this whole thing is good or bad. Personally, I think it is bad. And time will give us a definite answer.

Monday, June 17, 2013

Musicman reverse engineering challenge

Update: Here's the binary musicman.

I spent last week end solving some challenges in the DEFCON 21 CTF (qualification round). Among them, I like the third reverse engineering challenge, musicman, the most.

Musicman is kind of innovative. High level speaking, musicman is an echo server with a twist. It modulates bytes to frequencies thus transforms text strings to wave files. The goal of this challenge is to read the content of the file /home/musicman/key by communicating with the server over wave data. We do not send regular text commands anymore. We need to send wave files.

On start up, the server reads the content of the key file, transforms that into a wave file, and stores that to a global variable key.

Then it starts listening for new connection. When a connection arrives, the server sends a wave file that is the modulated form of the greeting string down to the client. Then the server goes into an infinite loop receiving wave file from client, and sending similar wave file back to client.

Each wave file uploaded by the client is converted into text string by the server. After that, the server prepends a string "You said: " to the converted text string. It then transforms this string into a wave file, and sends the wave file to the client.

All wave data (the received wave file, the modulated wave file) in this phase are stored in a global buffer named wav. The wave file that the client uploads goes to that buffer. The resulting wave file of text modulation goes to that buffer.

key and wav are adjacent to each other in the address space. key is at a lower address than wav. Both key and wav are 1.000.000-byte long.

So, basically, we need to understand the format of a wave file in order to talk to the server. With a little bit of research, this is the structure I found.

FOURCC riff_id;   // 'RIFF'
DWORD  riff_size; // remaining size of the file
                  // not including riff_id, and riff_size
FOURCC wave_id;   // 'WAVE'
FOURCC fmt_id;    // 'fmt'
DWORD  fmt_size;  // must be 0x10, the size of the
                  // WAVEFORMAT struct
WORD   wave_type; // must be 1, for PCM
WORD   nr_channs; // number of channels
DWORD  sample_rt; // samples per second
DWORD  byte_rt;   // bytes per second
WORD   block_alg; // block align
WORD   bits;      // bits per sample
FOURCC data_id;   // 'data'
DWORD  data_size; // size of remaining data after this
char[0] begin_data;

There are three size fields in this struct. The first one, riff_size, is the total data of the rest of the file. The second one, fmt_size, describes the size of the struct that follows it. If this is 16 byte long, it is WAVEFORMAT struct. It could also be WAVEFORMATEX, but we're not worrying about that here. The third field, data_size, is the size of remaining data.

The server does have pretty thorough checks on the received wave data. It makes sure that riff_id is RIFF, wave_id is WAVE and so on. More importantly, it makes sure that riff_size is appropriate for the 1.000.000-byte long buffer.

After passing all these sanity checks, the server starts demodulating wave data to string. But instead of getting to begin_data by a fixed offset value relative to the beginning of the file (riff_id), the server dynamically calculates that offset value by riff_size - data_size + 8.

There lies the problem. Unlike other fields, data_size is not checked. So if data_size is greater than riff_size, the offset value will be negative; we will point backwards.

Remember that all the wave data are stored in wav buffer, and key buffer is before wav. Hence, pointing backwards will mean that we'll be accessing key data. And that is how we're going to extract key.

The idea of exploitation is to send the server a fake wave file whose header's data_size is appropriately set so that the server will demodulate its own global key buffer. Then the server will prepend "You said: " to the resulting text string (which would be the content of the key file), modulate it to a wave file, and send that wave file to us.

But we've only got the wave file. We know that the wave file is the representation of the string You said: <key value>. We need to demodulate it. And that's easy because we can run a local copy of the server; we make it work for us. So we will set a breakpoint right after it has demodulated client's wave file (after RecvString function). Then we send our local server the received wave file that we've obtained from the actual server. When the breakpoint hits, we get the string.

Here's the script that talks to the original server, grabs its key wave data, and bounces that data to a local server on localhost.

from socket import *
import struct

HOST = ''
PORT = 7890

def read_n(s, l):
 r = ''
 while True:
  d = s.recv(l - len(r))
  if d == '':
  r += d
  if len(r) >= l:
 return r

s = socket(AF_INET, SOCK_STREAM)
s.connect((HOST, PORT))
data = read_n(s, 8)
header, data_len = struct.unpack('<4sI', data)
assert(header == 'RIFF')
remaining_len = data_len
read_n(s, remaining_len)
print 'Received first message', data_len

# now send some long wave data over there
riff_length = data_len + 100000
data = 'RIFF' + struct.pack('<I', riff_length - 8)
data += 'WAVEfmt ' + struct.pack('<I', 0x10)
data += struct.pack('<HHIIHH', 1, 1, 44100, 44100*2, 0, 16)
data += 'data'
data_length = riff_length - (len(data) + 4)
data += struct.pack('<I', data_length + 1000000 & 0xFFFFFFFF)
data += 'a' * data_length
print 'Sent our fake wave'

data = read_n(s, 8)
header, data_len = struct.unpack('<4sI', data)

data += read_n(s, data_len)
f = open('key.wav', 'w')
print 'Saved key.wav'

# connect to our own daemon, remember to run it in GDB to extract the key
s = socket(AF_INET, SOCK_STREAM)
s.connect(('localhost', 7890))
junk = read_n(s, 8)
header, data_len = struct.unpack('<4sI', junk)
read_n(s, data_len)


Monday, May 6, 2013

Lemon bars (or squares, or disks)

I baked my first cake today! Some lemon bars set in a round baking pan. Woot woot.

Monday, March 4, 2013

Cheats (or gems) come free in Eenies at War

Eenies at War is a Gunbound (or Worms) style massively multiplayer online game for iDevice from SavySoda. Eenies can be played offline too.

And like most games that are playable offline, Eenies stores its save game, which is called profile internally, on the device itself. SavySoda is well aware that this design decision raises many issues with cheats and hacks. And so they try to thwart the hackers by building in some hack detection code.

Among many checks that Eenies performs is a checksum check. Some attributes in the save game are used in calculating a MD5 value. The code is similar to:

NSString* playerId = profile.playerId;
int xp = profile.xp;
int gold =;
int gamesWon = profile.gamesWon;
NSString* s = [NSString stringWithFormat:
    @"Name: %@ Xp: %i Gold: %i Gems: %i Won: %i",
    playerId, xp, gold, gamesWon];
// and calculate MD5 value of s

Now, that code may not even compile, but that's not what I'm talking about. Hopefully you have spotted a real logic error in that code. Gold, gems, number of wins, player identity, and experience points are supposedly in the string to calculate MD5 for. Somehow, though, number of gems was missing in the stringWithFormat call!

What it means here is that you'd be able to freely change the number of gems you own (and everything else beside those attributes) if you were able to modify the save game. There are other minor hurdles to overcome on that front but I'm not going to talk about them. This particular bug is peculiar enough for me to write a post.

Leaving effectiveness aside, the fix is, of course, to put in the missing argument to that stringWithFormat call. Once again, security is unfunnily skewed.

Saturday, February 23, 2013

mysql_search: Automatically create fulltext indexes in MySQL with South

If you work with Django, you'll notice that Django has a search field lookup operation. I reckon that it is rarely used because it is firstly specialized for MySQL, and secondly demanding a FULLTEXT INDEX to be created externally. syncdb does not create fulltext indexes. Neither does South.

To overcome this limitation, I have created a little package called mysql_search. It extends South's MySQL DatabaseOperations class to add appropriate fulltext indexes to suitable fields. By "suitable" I mean fields whose class names are prefixed with Fulltext. This pattern is hard coded. After you have declared your fields, a migrate command will trigger necessary changes to add fulltext indexes to your table.

There are two caveats I need to mention. First, MySQL only supports fulltext index on MyISAM tables. Therefore, mysql_search will silently convert your tables to MyISAM if you declare any fulltext field in its model. You might want to create a separate model, that mirrors your actual model, whose sole purpose is to hold fulltext indexes. Second, mysql_search creates one fulltext index for one appropriate field. It does not create a combined index on multiple fields.

The package is released under the terms of the BSD license. Enjoy!

Sunday, January 20, 2013

How to win TapDefense

TapDefense is a good free tower defense game for iDevice.

This game is a little bit unusual in the genre. It has the "interest rate" concept that awards you gold based on your current gold, even if you lose the round. And that is important to know.

So, to beat this game, follow these steps:

  • Save money! SAVE MONEY! Seriously, if you can get through one round without spending and with few missed creeps, do it. You earn more money even if you do not fully clear the round. And the interest earns you so much more money if your pot is already big.
  • Put all your first few "halo" to increase your interest rate. You should do this until you reach about 20% interest (about level 16, I think).
  • Research only ice and storm. Ice should be researched first, then storm on later rounds.
  • Spread your storm towers out. You probably only need four of them.
  • Mingle ice towers in between storms. You'll need this so that the storm tower can target different creeps, instead of always aiming for the same guy.
  • Finish off the creeps with canon towers.
  • Initially, build one or two cannons, one or two waters, and maybe just one arrow.
  • Upgrade towers to the max. Upgraded towers are so much better than two, or three towers combined.

Tuesday, January 8, 2013

Sleep disorder

Someone once told me people sleep most deeply at around 3 o'clock in the morning. In the past few weeks, however, it has no longer been true to me. Recently, I've found that it is most difficult to sleep around that time. One eighty turn, I'd say.

By the way, here're two pictures of a butternut squash dish I made today ;). I learned the recipe from Ricky last Christmas.