SYSTEM] FSB 팁

노션으로 옮김·2020년 3월 12일
1

skills

목록 보기
16/37
post-thumbnail

읽어올 스택 인덱스 지정

포맷스트링에 매칭되는 스택의 위치를 임의로 지정할 수 있다.

32bit

printf("%4$x")
printf("%4$n")

64bit

printf("%4$lx")

또한 64bit는 인자값이 저장되는 순서와 위치가 다르므로 주의해야 한다.

7번째 인자부터 스택에 저장되므로, 7번째 인자를 1번째로 기준을 잡아야 한다.

main.c

#include <stdio.h>

void main()
{
  printf("%1$lx\n", 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70); 
  // Output value 0x10
}

디버깅

7번째 인자부터 스택에 저장된다는 점을 주의해야 한다.
%1lx lx ~ %5lx로 출력을 할 경우 RSI, ..., R9 까지의 레지스터 값이 출력된다.
%1lxRDI가아닌이유는,RDI는첫번째인자고첫번째인자는포맷스트링을나타내기때문.lx가 RDI가 아닌 이유는, RDI는 첫 번째 인자고 첫 번째 인자는 포맷스트링을 나타내기 때문. %6lx를 해야 스택의 값을 확인할 수 있다.


%hn

포맷스트링 버그를 수행하는데 2바이트만 수정해야할 경우가 있다.
대표적으로 다음과 같은 상황에 만날 수 있다.

%[주소값]x로 출력 문자열 수를 주소값만큼 늘려주고 %n으로 해당 주소값을 특정 위치에 덮어쓰려 한다.
하지만, 덮어써야할 주소값이 0xffffffff라면?
또한, 페이로드 크기도 제한되어 한 번의 입력으로만 주소값 overwrite를 성공해야 한다면?

%x로 출력가능한 문자열 수는 제한되어있기 때문에 0xff로 시작하는 주소값은 덮어쓸 수 없다.
그렇다면 다른 방법으로 해당 주소값을 덮어써야 한다.

대개 fsb로 이용하는 만들어내는 형태는 got overwrite가 일반적인데,
그렇다면 덮어쓸 함수(system)의 메모리상 주소값을 구하기 위해서 다른 함수의 실제 주소 값(printf) 또한 알고있을 것이다.

printf의 실제 주소값이 0xfbbb2030이라고 한다면, system의 주소값 또한 0xfbbb로 시작할 것이다.
굳이 4바이트가 아닌, 뒤에 2바이트만 덮어쓰면 된다는 얘기다.

%h[x|n|...else] 사용

half 기호를 통해 2바이트만 저장할 수 있다.
시스템 주소가 0xfbbb3040이라고 할 때,

%[0x3040]x%hn

의 페이로드를 이용해서 2바이트 수정으로 시스템 주소값을 만들어낼 수 있다.

주의할점

일반적으로 리틀 엔디안 방식을 사용해 주소값이 거꾸로 저장되므로
하위 2바이트값을 수정하기 위해선
해당 주소값의 시작위치에 덮어쓰면 된다.

예를 들어, 0x10101010위치에 덮어쓰려고 한다면
하위 2바이트를 저장할 것이므로 0x10101010+2에 덮어쓰는게 아니라
그냥 0x10101010에 덮어쓰면 된다.

0개의 댓글