Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ptrace Segmentation Fault signal handler can't handle RETurns to invalid addresses #77

Open
AlLongley opened this issue Jan 15, 2023 · 1 comment

Comments

@AlLongley
Copy link

AlLongley commented Jan 15, 2023

Trying to _analyze() or display() a ProcessSignal of type SIGSEGV raised by a "RET" condition currently raises an Exception, as the current instruction handler has no detection for the RET opcode.

This segfault signal can be raised when an invalid address is at the top of the stack, then a RET is executed looking to pop the value into RIP. This is a valuable use-case for detecting buffer overflows / attempted RET2Libc attacks in binaries without stack protection canaries

@AlLongley
Copy link
Author

I propose an addition to the following function:

def memoryFaultInstr(self, instr, fault_address):
asm = instr.text
# Invalid write (e.g. "MOV [...], value")
match = re.search(r"^(?:MOV|TEST)[A-Z]* %s," % DEREF_REGEX, asm)
if match:
if fault_address is None:
fault_address = evalFaultAddress(self.process, match)
self.reason = InvalidWrite(fault_address, size=findDerefSize(match),
instr=instr, process=self.process)
return

With the following opcode check:

# RET instruction (e.g. "RET" with an invalid return address at the stack pointer)
match = re.search(r"^(?:RET?)?", asm)
if match:
	sp = self.process.getStackPointer()
	return_addr = self.process.readWord(sp)
	
	self.reason = InvalidRead(address=return_addr, size=CPU_WORD_SIZE, process=self.process)
	return

My main issue halting PR is that my RegEx skills are garbage, and I don't quite understand the re.match groups referenced in the previous opcode checks.

I understand they match for variations of the regular opcodes, and extract out the operands for calculating memory accessed by specific offsets, though I don't believe RET has any variations or operands.

Is my sample code above a valid check? And is simply readWord() from the StackPointer a safe operation between 32 and 64 bit archs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant