Partial Overwrite
Sistemas modernos têm ASLR, todos os endereços de memória são randomizados toda vez que o programa roda. Assim, não sabemos para onde apontar para fazer os ROPs!
A solução para isso é fazer o Partial Overwrite.
Os endereços de memória como 0x7ffd4a3b12e0 são compostos de:
- Bytes mais significativos:
0x7ffd4a3b- Randomizado pelo ASLR! - Bytes menos significativos:
0x12e0- Muitas vezes previsível ou com variação limitada
Com ASLR, geralmente apenas os primeiros bytes (mais significativos) são randomizados. Os últimos bytes (menos significativos) frequentemente mantêm padrões.
Mesmo programa, execuções diferentes:
Execução 1: 0x7f8a1b45[1200] ← ASLR muda ESTA parte
Execução 2: 0x7f4c2d89[1200] ← ASLR muda ESTA parte
Execução 3: 0x7e9b3fa2[1200] ← ASLR muda ESTA parte
↑
Esta parte geralmente FICA IGUAL (offset relativo)
Imagine o programa inteiro como uma caixa. Você pode sempre mudar a caixa de lugar em um galpão, mas todas as partículas do papelão estarão à uma mesma distância umas das outras, certo?
No partial overwrite, não sabemos os bytes mais significativos, mas sabemos o offset relativo dado ao endereço desejado. Assim:
- Temos um endereço legítimo na pilha
0x7f8a1b451200que aponta para dentro de um módulo (libc, etc) - Não sabemos que o endereço é
0x7f8a1b451200, mas ele está lá. - Não modificamos os bytes mais significativos (
0x7f8a1b45), pois não sabemos quais são. Modificamos apenas os bytes menos significativos (0x1200 → 0x1250), pois:- Conhece-se o layout do módulo (distância dos gadgets, ou offset, em relação à aquele endereço)
- Sabe-se que os gadgets estão em
+0x50,+0x80, etc., do endereço atual (USAMOS ISSO!)
O Partial Overwrite funciona:
- Quando você não sabe o endereço absoluto (randomizado pelo ASLR) do gadget
- Se você tem um endereço válido na pilha que possa ser manipulado
- Se você sabe o layout relativo do módulo (onde os gadgets estão em relação ao endereço atual)
- Se você sabe que os offsets relativos são consistentes (gadget sempre estará a
+0x50bytes)
Assim, a tática é reutilizar um endereço já existente na pilha e obter todos os gadgets a partir do endereço relativo dos gadgets em relação a ele.