четверг, 21 мая 2020 г.

kernel pte in windows 10 64bit

Quarantine is a good time to re-read some old but useful papers and check if you can catch trick with making KUSER_SHARED_DATA writable again So lets see what we need:
  • some logic to extract PTE base from MiGetPteAddress
  • primitive to check if some address is valid - I used MmIsAddressValid
  • primitive to read page from kernel memory
Start with some system info:
pSystemRangeStart: FFFF800000000000
PTE base address: FFFF880000000000
PTE mask: 7FFFFFFFF8
PTE shift: 9

Do some calculation
function to get offset to PTE looks like:
return (address >> 9) & 0x7FFFFFFFF8;

for pSystemRangeStart PTE will be
4000000000 + pte_base = FFFF884000000000
You may notice that this address located above pte_base

for last available address in system FFFFFFFFFFFFFFFF PTE will be
7FFFFFFFF8 + pte_base = FFFF887FFFFFFFF8

Also we need some inverse function to convert from PTE to page address. First we need sub pte_base, then divide on sizeof(MMPTE_HARDWARE) and then multiply to size of page. And add some base address. Try to calculate this base for example for PTE of pSystemRangeStart FFFF884000000000:
(FFFF884000000000 - FFFF880000000000) / sizeof(MMPTE_HARDWARE) * 0x1000 = 800000000000

Our base is FFFF800000000000 (value of pSystemRangeStart) - 800000000000 = FFFF000000000000

Notice that this base does not match with pSystemRangeStart
So our inverse function may looks like:
return 0xFFFF000000000000 + (ptr_addr - pte_base) / sizeof(MMPTE_HARDWARE) * 0x1000;

Ok, it seems that we have all puzzle pieces and can scan all PTE from FFFF884000000000 to FFFF887FFFFFFFF8. Yes, all 0x4000000000 bytes - 256Gb. Sure, we can wait for results before retirement

вторник, 5 мая 2020 г.

afd endpoints owner

Alex and Yarden as usually made perfect work to bypass even paranoid EDRs
The main problem is detection of duplicated sockets. There is a hint however:
all ownership of the socket still belongs to the original creator – even when the creator exists (and actually, because Netio.sys is still referencing the original EPROCESS, the creator and the PID become “zombies” and leak resources).
o`k, reason is true, but reference holds by afd.sys. Lets see why
We need disasm 2 functions to write simple script. First - we need back offset from afd!AfdEndpointListHead to read endpoint. It can be extracted from AfdIsAddressInUse:
  mov     [rsp+arg_0], rbx
  mov     [rsp+arg_8], rbp
  mov     [rsp+arg_10], rsi
  push    rdi
  sub     rsp, 30h
  mov     rsi, rcx
  xor     ebx, ebx
  mov     rcx, cs:AfdGlobalData
  call    cs:__imp_ExEnterCriticalRegionAndAcquireResourceShared
  nop     dword ptr [rax+rax+00h]
  mov     rdi, cs:AfdEndpointListHead
  lea     rbp, AfdEndpointListHead
  jmp     short loc_1C003C0D3
; ---------------------------------------------------------------------------

loc_1C003C054:                          ; CODE XREF: AfdIsAddressInUse+BE
  lea     rdx, [rdi-120h]
...
loc_1C003C0D3
  cmp     rdi, rbp
  jnz     loc_1C003C054


Then we need offset to EPROCESS - it can be extracted for example from AfdFreeEndpointResources:

  mov     rcx, [rbx+28h]
  mov     edx, 200h
  call    cs:__imp_PsReturnPoolQuota
  nop     dword ptr [rax+rax+00h]
  mov     rcx, [rbx+28h]  ; Object
  call    cs:__imp_ObfDereferenceObject


Now we have all parts of this puzzle. Let`s see what we can do in windbg