Home Buffer Overflow
Post
Cancel

Buffer Overflow

Reverse engineer

Theory

GOT

The Global Offset Table (or GOT) is a section inside of programs that holds addresses of functions that are dynamically linked. As mentioned in the page on calling conventions, most programs don’t include every function they use to reduce binary size. Instead, common functions (like those in libc) are “linked” into the program so they can be saved once on disk and reused by every program.

Unless a program is marked full RELRO, the resolution of function to address in dynamic library is done lazily. All dynamic libraries are loaded into memory along with the main program at launch, however functions are not mapped to their actual code until they’re first called. For example, in the following C snippet puts won’t be resolved to an address in libc until after it has been called once:

1
2
3
4
5
int main() {
    puts("Hi there!");
    puts("Ok bye now.");
    return 0;
}

PLT

Before a functions address has been resolved, the GOT points to an entry in the Procedure Linkage Table (PLT). This is a small “stub” function which is responsible for calling the dynamic linker with (effectively) the name of the function that should be resolved.

Reversing

Remember to use:

1
2
3
ltrace [Binary]
strace [Binary]
strings [Binary]

Spinking with python easy

1
for i in {1..50}; do echo $i; ltrace ./binary `python -c "print 'a'*$i"`; done

Note: It is not necessary the ltrace command

Another spiking and fuzzing shortcut

1
2
3
4
5
6
7
8
9
10
11
12
13
$ pwn cyclic 40
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

$ echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" | ./binary
This can create weird output, use dmesg to get the eip position 


$ dmesg | tail
Get the eip pattern

$ pwn cyclic -l [eip pattern]
Return the offset of the eip

Hex to Raw with python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python

from pwn import *

flag = ""
flag += p32(0x[NUM])
flag += p32(0x[NUM])
flag += p32(0x[NUM])
flag += p32(0x[NUM])

print(flag)

p = remote('url', port)
elf = ELF('path of the binary')
p = elf.process()

# Getting the input from pwn

var = p.recv()

# int(value_of_string,16)

# Send input
p.sendline(payload)

# Show a verbose mode
p.interactive()



Always to remember, it is not necessary to do a reversing to a function, we can try to brute force the response.

1
2
3
4
5
6
7
8
9
10
import string

flag = list('THM{')
while(1):
    for character in string.printable:
        output = function("".join(flag) + character)
        if(output.startswith(out)):
            # There's a finding folks
            flag.append(character)
            print "".join(flag)

For the APK, you can extract the data (because is an archive) We can unzip it with APKTOOLS

1
apktool d [apk_file]

The smali is where the program resides. Always look for the MainActivity.smali

1
xdd is your friend, you can hexdump everything and do the reverse

What if you find a static path and the binary needs to open it? Can you move the binary and fake the file that has to be open? Opening files is dangerous!

Using pwn tools to change de behaviour of the binary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python

from pwn import *
elf = ELF("PATH")
new_key = "10298371092836123123124104876123"
# Looking for symbols
for key,address i elf.symbols.iteritems():
    print key,hex(address)

# This change the symbol (In this example the function alarm)
elf.asm(elf.symbols['alarm'],'ret')
# In this case the number is tooo big, so, we make it small with the &
elf.asm(elf.symbols['key'],'mov eax,%s\nret\n' % (hex(new_key & 0xFFFFFFFF)))
elf.save("NEW BINARY FILE")

Checksec can help to know what protections does a binary have

1
$ checksec [Binary]

Relro: A dynamically linked ELF binary uses a look-up table called the Global Offset Table (GOT) to dynamically resolve functions that are located in shared libraries. Such calls point to the Procedure Linkage Table (PLT), which is present in the .plt section of the binary. The .plt section contains x86 instructions that point directly to the GOT, which lives in the .got.plt section. GOT normally contains pointers that point to the actual location of these functions in the shared libraries in memory. The GOT is populated dynamically as the program is running. Solution:This technique is called RELRO and ensures that the GOT cannot be overwritten in vulnerable ELF binaries.

A PIE binary and all of its dependencies are loaded into randomized locations within virtual memory each time the application is executed. This makes Return Oriented Programming (ROP) attacks much more difficult to execute reliably.

Readelf helps to find where are the functions of the binary located. Caution, if the binary uses PIE, then the hex values in the readelf output DOES NOT represents the actual position of the function.

1
$ readelf -s [binary]
This post is licensed under CC BY 4.0 by the author.