Methodology
Random general tips and notes I need to remind myself of.
Document the attack surface:
Recon:
Review the applications memory protections (DEP/ASLR/Etc)
Do your research before doing any reverse engineering:
Read any relevant RFCs for the protocols used.
Read any technical documentation of file formats used.
Read the docs.
Locate an entrance point to the application via ProcMon/Netstat/etc
Enumeration:
Do an intial pass with both dynamic and static analysis to get a very broad idea of what the application is doing with your data.
Note any DLLs called and repeat step 2 for them as necessary.
Start with several full fast passes to get a general understanding.
Don't commit to in depth RE until you are relatively sure you understand the basic flow of the application.
Note suspicious code for later review.
RE:
Just because there are no obviously vulnerable system calls doesn't mean you should skip over a function. For example loops and rep movs as well as a single mov r32, r32 can lead to an overflow or write primitive.
Always send the largest possible buffer to every new path.
Follow calls to other DLLs and put them in IDA for analysis.
Note every opcode tested and go through them in numerical order so you don't miss any. Can use alt+t in IDA to search for cases.
If a function requires some specific input like a filename attempt adding another buffer after the file seperated by a nullbyte/newline/CR
Exploitation:
Check various buffer sizes
In the case where a read is being preformed on user controlled data attempt to increase both the read and the write buffer sizes.
This includes when attempting to cause a crash for SEH overflows.
ROP selection:
Locate write gadget: mov [write], read
gadgets write register must
receive a writable staging area address
increment
decrement by ~0x18
gadgets read register must
receive staging area address
receive dereferenced function address
recieve shellcode address
receive arbitrary small values (ideally pop + neg/sub)
Commonly Vulnerable Calls
(As well as the various derivates of the below functions)
gets
scanf
memcpy
wctomb
mbtowc
strcpy
strcat
sprintf
MultiByteToWideChar
https://www.proggen.org/doku.php?id=security:memory-corruption:protection:stdlib
Suspicious Assembly
From The Shellcoder's Handbook chapter 21:
Variable Indexed write
mov [ecx+edx], al
Write to pointer followed by increment of pointer
mov cl, [edx]
movsx eax, cl
Add/sub from a register containing controlled data:
mov eax, [edi]
add eax, 2
cp eax, 256
jae error
Value truncation as a result of being stored as a 16- or 8-bit integer
push edi
call strlen
add esp, 4
mov word ptr [ebp-4], ax
Vulnerability Classes
The Shellcoder's Handbook chapter 18
Generic Logic Errors
Unbounded Memory Copy Functions (mostly extinct)
strcpy
sprintf
strcat
gets
Format Strings
See Format String Attack notes
Incorrect Bounds-Checking
Loop Bugs
loops introduce complexity especially in edge cases
Off-by-One
Often occur when working with strings such as incorrectly calculating the length of a strncat which includes an extra nullbyte by default.
OpenBSD ftp Daemon Example (off by one when the string ends in a "):
char npath[MAXPATHLEN];
int i;
for (i = 0; *name != β\0β && i < sizeof(npath) - 1; i++, name++)
{
npath[i] = *name;
if (*name == βββ)
npath[++i] = βββ;
}
npath[i] = β\0β;
Non-Null Termination/Skipping Null Termination:
If a string fails to contain a nullbyte subsequent function calls may include large amounts of additional data from the buffer location (ie strcpy).
Skip example from Apache mod_rewrite:
else if (is_absolute_uri(r->filename)) {
/* it was finally rewritten to a remote URL */
/* skip βscheme:β */
for (cp = r->filename; *cp != β:β && *cp != β\0β; cp++)
;
/* skip β://β */
cp += 3;
Works for https:// but ldap:a will lead to the nullbyte being skipped.
Signed Comparison:
Negative numbers for length specifiers provided by a user (such as within a packet) may lead to unintended behavior.
Example from Apache chunk-encoding vulnerability:
//r->remaining is user supplied, providing a negative number leads to a buffer overflow
len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
len_read = ap_bread(r->connection->client, buffer, len_to_read);
Integer Overflows:
16 bit (short) signed integar
max value: 0x7fff
min value: 0x8000
16 bit unsigned integar
max value: 0xffff
32 bit (long) signed integar
max value: 0x80000000
min value: 0x7fffffff
32 bit unsigned integar
max value: 0xffffffff
Example:
//if n is user supplied and less than HEADER_SIZE
memcpy(dest,data+HEADER_SIZE,n β HEADER_SIZE);
Integer Conversions:
" ... if a signed 32-bit integer with a negative value of β65,535 were changed to a 16-
bit integer, the resulting 16-bit integer would have a value of +1 due to the
truncation of the highest 16 bits of the integer."
Double Free:
When a heap chunk is freed more than once. Difficult to exploit in practice.
https://sensepost.com/blog/2017/linux-heap-exploitation-intro-series-riding-free-on-the-heap-double-free-attacks/
Uninitialized Variable Usage
Use After Free
Last updated
Was this helpful?