FROM CRASH TO CODE EXECUTION
this is my first time giving a try into a windows x64 bits , and challenges offered by blue frost security
I’ve decided to give the 2019 BFS Exploitation Challenge a try. It is a Windows 64 bit executable\ for which an exploit is expected to work under Windows 10 Redstone 6
The Rules
- Bypass ASLR remotely
- 64-bit version exploitation
- Remote Execution
Inital Steps
we were given a windows binary only . this made me think, I cannot use any fuzzing technique because I dont know if it’s local or remote . let’s try doing some reverse engineering before, So I can understand what it is really doing.
Navigating through the main function , we notice that it is a remote application which listen to 54321
Identifying the Vulnerability
by disassembly the function , it is obvious that some checks need to bypassed in order to send send our payload correctly
- if ( v6 == 16i64 )
- if ( *(_QWORD *)buf == ‘0x393130326F6B45’ )
- strcpy(buf, “Eko2019”);
- if ( size_data <= 512 )
- if ( (signed int)size_data % 8 )
the first validation our application is checking if our payload is equal to 16 bytes , then if buf
is equal to 0x393130326F6B45
which trasnalte into 9102okE
in hex. there is a strcpy that copy at the end of our payload Eko2019
, but we also have a size data validation which\ we cannot send more than 512 bytes , and it needs to be aligned correctly for 8 bytes. meaning we could send 8,16,24
so on
the “jle” instruction indicates a signed integer comparison, but later passed as unsigned which lead us an integer overflow
after we successfully send a bigger payload, I notice it crashes after sending 229 bytes
, but before that there is a instruction lea rcx, unk_7FF6A8A9E520
, but what unk_7FF6A8A9E520
is holding or doing? after inspectioning deeper about this unk_7FF6A8A9E520
. we found there is an array with an offset of 256
with this structure
the functionsub_7FF6A8A91000
will return our byte + 488B01C3C3C3C3h
in this case 41 48 8B 01 C3 C3 C3 C3
this value will basically be used in the WriteProcessMemory(v2, sub_7FF7DD111000, &Buffer, 8ui64, &NumberOfBytesWritten);
as buffer these to the function sub_7FF6A8A91000
as instructions allowing to control what we can execute when we reach it.
we could see rax , and rcx
was overwritten , but however rax
was overwritten only one byte from the lower bytes, and rcx
overwrite completely causing an access violation
.text:00007FF7DD111000 arg_0= qword ptr 8
.text:00007FF7DD111000
.text:00007FF7DD111000 db 42h
.text:00007FF7DD111000 mov rax, [rcx]
.text:00007FF7DD111004 retn
why does this happen?
there’s a reason
- because of the value of the pointer of RCX that you control
Strategy
In order to bypass ASLR, we need to cause the server to leak an address that belongs to its process space. Fortunately, there is a call to the send()
function , which sends 8 bytes of data, so exactly the size of a pointer in 64 bit land. That should serve our purpose just fine.
qword_7FF7DD11D4E0 = printf(aRemoteMessageI, (unsigned int)counter_conection, &Dst);
++counter_conection;
Buffer = what_the_heck_do(array[byte % -256]);
v2 = GetCurrentProcess();
WriteProcessMemory(v2, sub_7FF7DD111000, &Buffer, 8ui64, &NumberOfBytesWritten);
*(_QWORD *)v3 = sub_7FF7DD111000(v9);
send(s, v3, 8, 0);
result = 1i64;
The strategy is getting control of the “byte” variable Luckily, it is a stack variable adjacent to the “size_data[512]” other than the default one at index 62 (0x3e).
I wrote a simple script to find gadgets in order to leak data from the running process
for i in $(cat file); do echo -e "\n$i" && rasm2 -b -D $i;done
after sometime research how I can read some information about the running process . I found what I could read via gs
(segment register) because of x64 bits
0x65488B01C3C3C3C3
0x00000000 4 65488b01 mov rax, qword gs:[rcx]
0x00000004 1 c3 ret
0x00000005 1 c3 ret
0x00000006 1 c3 ret
0x00000007 1 c3 ret
So this special register which could lead us to read _PEB
, and our peb
offset is at +0x060 ProcessEnvironmentBlock : Ptr64 _PEB
via dt ntdll!_TEB
preparing our exploit
Leaking the PEB
- 0x65 = mov rax, qword gs:[rcx]
- 0x060 = _PEB
WINDBG>dt ntdll!_TEB
+0x000 NtTib : _NT_TIB
+0x038 EnvironmentPointer : Ptr64 Void
+0x040 ClientId : _CLIENT_ID
+0x050 ActiveRpcHandle : Ptr64 Void
+0x058 ThreadLocalStoragePointer : Ptr64 Void
+0x060 ProcessEnvironmentBlock : Ptr64 _PEB
+0x068 LastErrorValue : Uint4B
+0x06c CountOfOwnedCriticalSections : Uint4B
+0x070 CsrClientThread : Ptr64 Void
+0x078 Win32ThreadInfo : Ptr64 Void
+0x080 User32Reserved : [26] Uint4B
in order to make our exploit to leak the data . we need to find a way to derefence rcx
with our _PEB
offset\ So we can leak our PEB address to start leaking data to bypass ASLR
Leaking the ImageBaseAddress
WINDBG>dt ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 BitField : UChar
+0x003 ImageUsesLargePages : Pos 0, 1 Bit
+0x003 IsProtectedProcess : Pos 1, 1 Bit
+0x003 IsImageDynamicallyRelocated : Pos 2, 1 Bit
+0x003 SkipPatchingUser32Forwarders : Pos 3, 1 Bit
+0x003 IsPackagedProcess : Pos 4, 1 Bit
+0x003 IsAppContainer : Pos 5, 1 Bit
+0x003 IsProtectedProcessLight : Pos 6, 1 Bit
+0x003 IsLongPathAwareProcess : Pos 7, 1 Bit
+0x004 Padding0 : [4] UChar
+0x008 Mutant : Ptr64 Void
+0x010 ImageBaseAddress : Ptr64 Void this our value we want to leak now
+0x018 Ldr : Ptr64 _PEB_LDR_DATA
+0x020 ProcessParameters : Ptr64 _RTL_USER_PROCESS_PARAMETERS
+0x028 SubSystemData : Ptr64 Void
+0x030 ProcessHeap : Ptr64 Void
+0x038 FastPebLock : Ptr64 _RTL_CRITICAL_SECTION
+0x040 AtlThunkSListPtr : Ptr64 _SLIST_HEADER
+0x048 IFEOKey : Ptr64 Void
+0x050 CrossProcessFlags : Uint4B
....snip
Code execution