Sam Symons

Software Security Course Review

As a follow up to the crypto course from earlier this year, I enrolled in the software security course from the University of Maryland for something a bit more hands-on.

I wanted to write up a short review of the course here, especially since I haven’t seen many (any?) other security courses like this offered on Coursera.

Overview

The syllabus is what you would expect in a security course:

  1. Low-level, memory-based attacks
  2. Defenses against memory-based attacks
  3. Web security
  4. Secure design
  5. Automated code review with static analysis and symbolic execution
  6. Penetration testing

You can see that the course is roughly divided up into two different sections: attacking, and defending. Each section goes over the ways certain areas of software can be exploited (say, via SQL injection), and then it is followed up by how you would defend against that problem (sanitizing user input in this case).

Workload

The workload for this course was surprisingly light; I would often sit down early Monday morning and work through the week’s content before lunch. The same can probably be said of other courses; with Software Security I enjoyed it enough that it was easy to just work through all of it at once.

Each week has the usual set of lecture videos paired with a quiz, and then every other week had an assignment to go with it. Each assignment involves firing up a Linux VM and running through some problems, like taking down a vulnerable web app or exploiting stack overflows via GDB.

Final Notes

With courses I’ve taken in the past, I’ve gone the lone wolf approach and tried to do the content myself without asking for any help (besides reading books).

This time, I jumped into the ##softwaresec IRC channel on Freenode and got to know people there. Having to explain concepts to people was far more helpful at making sure I understood the material than simply taking notes and answering quiz questions.

This was a great course, and I’d love to see a follow-up to it in the future.

NASM Tutorial

A simple (and understandable) intro to writing Assembly with NASM. I spent a solid amount of time with this article this morning – it’s great.

Exploit Exercises Protostar Guide, Part 1

In order to better understand the material from the Software Security course on Coursera, I decided to take a stab at the challenges on Exploit Exercises.

So far it has been an amazing way to really cement the concepts from the course, so I decided to document my progress here for anybody else interested in making their way through the levels.

I’ve been running through these challenges by setting up the downloadable ISOs from the Exploit Exercises downloads page in VirtualBox, then sshing in so I don’t have to deal with VirtualBox as much.

Stack 0

In stack0, the program defines an int variable named modified, followed by a 64 byte char buffer. It then gets input from STDIN, using buffer as its destination, before printing a string dependent on the contents of modified.

By passing input with a length greater than 64 bytes to the program, the buffer variable will overflow onto the modified variable, giving you the target output. The first 64 bytes will fill the buffer, with the 65th byte overwriting the value of modified.

echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | ./stack0

Typing all those characters is exhausting though. Let’s use Ruby.

ruby -e "puts('A' * 65)" | ./stack0

Stack 1

This program expands upon the previous example by requiring that you use a specific value as your overflow. It works similarly to stack0, except the exploit only succeeds when modified matches 0x61626364.

To fill the buffer variable, we again need 64 bytes of padding, followed by the value to overwrite modified with. The value 0x61626364 conveniently matches the first 4 lowercase alphabetical characters in the ASCII character set (abcd). By adding that to the end of the padding string, the conditional should succeed.

There’s one caveat: the VM that Protostar is running in is little-endian, meaning that the order of the characters needs to be reversed before being appended to the string.

./stack1 `ruby -e "puts(('A' * 64) + 'dcba')"`

Stack 2

This challenge is very similar to the previous one, except that the malicious string needs to be set as an environment variable instead.

Note that I’m also using hex values directly, as these don’t nicely translate to ASCII characters.

GREENIE=`ruby -e "puts(('A' * 64) + \"\x0a\x0d\x0a\x0d\")"`
export GREENIE
./stack2

Stack 3

This challenge asks us to overwrite a pointer value stored on the stack with that of another function. The tricky aspect of this one is finding the address of the function we want to call.

objdump is a tool which prints information about binaries – time to put it to use by finding the address of the win function.

$ objdump -d stack3 | grep win
08048424 <win>:

The address of win looks to be 0x08048424. Nice! That will serve as the value of our overflow, formatted as little-endian once again.

ruby -e 'puts(("A" * 64) + "\x24\x84\x04\x08")' | ./stack3

Stack 4

This was a pretty fun challenge to figure out. The idea is that you have to overwrite the eip pointer on the stack, while dealing with the compiler which will insert an undetermined amount of padding between you and eip on the stack.

After some research, I found a few mentions of a technique used to exploit code like this. The idea is to generate a unique, non-repeating string, and use that to find the offset by providing it as the value of the overflow.

I used this handy tool to generate a string. Pass that string to the program, and look at the result when it hits eip. (A quick note on this part: you will need to open and run the program in gdb to see the value that is being called.)

Take the value and pass it back to the buffer overflow tool to figure out the offset (76, in this case). Use objdump to find the address of win once more, and then you have yourself an exploit.

ruby -e 'puts(("A" * 76) + "\xf4\x83\x04\x08")' | ./stack4
← Next Page