[Dreamhack] kidding
[Dreamhack] kidding
문제 링크
https://dreamhack.io/wargame/challenges/1679
문제 설명
https://www.youtube.com/watch?v=rDFUl2mHIW4
문제 분석
scanf
함수로 스택 버퍼 오버플로우가 발생하는 바이너리를 python qiling 라이브러리로 에뮬레이팅한다.qiling 라이브러리 코드에 일부 수정이 이루어진 후 실행된다. (apply.diff)
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
diff --git a/qiling/loader/elf.py b/qiling/loader/elf.py index 1a00bcec..8be543f5 100644 --- a/qiling/loader/elf.py +++ b/qiling/loader/elf.py @@ -5,9 +5,11 @@ import io import os +import random +import time from enum import IntEnum -from typing import AnyStr, Optional, Sequence, Mapping, Tuple +from typing import AnyStr, Optional, Sequence, Mapping, Tuple, Union from elftools.common.utils import preserve_stream_pos from elftools.elf.constants import P_FLAGS, SH_FLAGS @@ -70,6 +72,7 @@ class QlLoaderELF(QlLoader): super().__init__(ql) def run(self): + random.seed(int(time.time())) if self.ql.code: self.ql.mem.map(self.ql.os.entry_point, self.ql.os.code_ram_size, info="[shellcode_stack]") @@ -286,11 +289,14 @@ class QlLoaderELF(QlLoader): return top - def __push_str(top: int, s: str) -> int: + def __push_str(top: int, s: Union[str, bytes]) -> int: """A convinient method for writing a string to stack memory. """ + if isinstance(s, str): + return __push_bytes(top, s.encode('latin')) - return __push_bytes(top, s.encode('latin')) + if isinstance(s, bytes): + return __push_bytes(top, s) # write argc elf_table.extend(self.ql.pack(len(argv))) @@ -316,7 +322,7 @@ class QlLoaderELF(QlLoader): # add a nullptr sentinel elf_table.extend(self.ql.pack(0)) - new_stack = randstraddr = __push_str(new_stack, 'a' * 16) + new_stack = randstraddr = __push_str(new_stack, random.randbytes(16)) new_stack = cpustraddr = __push_str(new_stack, 'i686') new_stack = execfn = __push_str(new_stack, argv[0])
- 현재 시간을 시드 값으로 설정한다. (
random.seed(int(time.time()))
) - 기존에는 “a” 16바이트가 스택에 삽입되었으나, 코드 수정 결과 랜덤한 16바이트가 스택에 삽입된다.
- 이때 삽입되는 16바이트는
AT_RANDOM
값으로, 스택 카나리가 결정될 때 사용되는 값이다. - 스택 카나리는
AT_RANDOM[:8]&(~0xff)
으로 결정된다.
- 이때 삽입되는 16바이트는
- 현재 시간을 시드 값으로 설정한다. (
- 스택 카나리가 랜덤화되었으나, 시드값이 현재 시간이므로 서버와 동일한 순간에 시드를 설정하면 동일한 스택 카나리를 얻을 수 있다.
- 이후 스택 버퍼 오버플로우로 rop payload를 전송하여 실행한다.
- 이유는 모르겠으나
system("/bin/sh")
,execve("/bin/sh", NULL, NULL)
모두 호출에 실패하였다.. - 대신
read(0, bss, 0x40)
으로 파일명 입력 ->open(플래그, O_RDONLY)
->read(3, bss, 0x50)
->write(1, bss, 0x50)
순서로 rop payload를 작성하여 해결하였다.
- 이유는 모르겠으나
새롭게 알게된 점
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.