Pular para o conteúdo principal

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:

  1. Temos um endereço legítimo na pilha 0x7f8a1b451200 que aponta para dentro de um módulo (libc, etc)
  2. Não sabemos que o endereço é 0x7f8a1b451200, mas ele está lá.
  3. 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 +0x50 bytes)

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.