uaf
디렉토리
uaf.cpp
Human 클래스
Man 클래스 Woman 클래스
main
case 1
일단 문제 이름도 uaf인 만큼 간단히라도 알고 들어가자.
UAF(Use After Free)
heap영역에서 할당된(allocated) 공간을 free하고 재사용(reuse)할 때 일어날 수 있는 취약점
heap spray와 병행해서 사용
포인트
1. uaf
2. give_shell
m,w 할당됐던 자리에 메모리를 집어넣어 give_shell 재사용
-> uaf는 free한 메모리를 재사용하는 것이기 때문
순서: case3 -> case2 2번 -> case1
1. case3으로 m, w을 free
2. case 2 2번(64bit이기 때문에 4byte주소 2번 넣음)으로 introduce주소를 give_shell 주소로 교체한 후
3. case 1로 introduce에 있는 give_shell 호출
m, w할당 후 heap
0x401570에 Man, 0x4015a0에 Woman이 할당되어 있다.
0x40117a부터 함수가 저장되어 있다.
0x40117a : give_shell, 0x4012d2 : introduce
give_shell 주소 : 0x40117a
1. case 3 실행
m, w free 후 heap
free 후에는 m, w를 가리키는 주소가 0xffffffff로 변한다.
2. case 2 실행
이때, 이전에 동적 할당했던 크기와 같거나 작게 할당해야 한다.
m(w)보다 크게 할당하면 다른 주소에 할당됨
m크기=w크기=40byte(최대 크기)
0xxxx50에 있는 주소를 이용해야 되기 때문에 24byte 이하로 할당하자.
왜?
-> 24byte 까지만 밑에서 채워진다.
처음 4byte 할당하면 0xxxa0에 0x0000000000401568 저장됨
두번째 4byte 할당하면 0xxx50에 0x0000000000401568 저장됨
3. case 1 실행
원래 case 1 실행순서
1. rbp-0x38 = m객체의 메소드의 시작주소 목록이 저장된 주소 = 0xxx50
2. rax = 0xxx50에 저장된 값(주소) = 0x401570 give_shell 시작주소
3. rax+0x8 = 0x401578 = introduce 시작주소
4. rdx = rax+0x8에 저장된 값(주소) = introduce 시작주소
5. call rdx = introduce 호출
이걸 이용해서
1. rbp-0x38 = 0xxx50 (ex. 0x1a99c50)
2. rax = 0xxx50에 저장된 값(주소) = 0x401570
* 0x401570에 저장된 값(주소) : 0x40117a = give_shell 주소
3. rdx = rax+0x8에 저장된 주소
4. call rdx -> 결국 rdx에 give_shell의 주소가 들어가면 된다.
입력값 + 8 에 저장된 주소 = 0x40117a
입력값 + 8 = 0x401570
입력값 = 0x401568
자 입력해보자.
참고
1. 스택과 힙
스택 : 정적 할당이기 때문에 컴파일 시 미리 스택에 공간 할당된다.
스택에 생성될 배열 사이즈가 상수로 고정될 수 밖에 없다.
주소가 낮아지면서 할당된다.
힙: 동적 할당(런타임)되는 영역으로 바이너리 실행되고 죽기 전까지 힙에 데이터가 남아있다.
힙에 생성될 배열 사이즈는 임의로 바꿀 수 있다.
주소가 높아지면서 할당된다.
2. free후 할당한 크기에 따른 data 저장
1) 4byte씩 할당 : 0xxxa0 저장 -> 0xxx50저장
2) 16byte씩 할당 : 0xxxa0 저장 -> 0xxx50 저장
3) 24byte씩 할당 : 0xxxa0~0xxxb8, 0xxx50~0xxx68
4) 32byte씩 할당 : 0xxx70~0x90, 0xxx20~0xxx40
5) 40byte씩 할당 : 0xxx70~0xxx98, 0xxx20~0xxx48