overlapping chunk 두번째 자료이다.

이 자료 또한 어떠한 문서를 참조했다고 나와있었다.



(참조 문서)


그렇기에 나 또한 이 참조 문서 먼저 공부하였다.
이 문서에는 Heap overlapping에 관해서 3가지 정도의 방법을 제시했다.
Heap Overlapping에 관해 조금씩 다른 방법들을 제시했는데,
다들 비슷비슷한 느낌이었다. 그래도 많은 방법들을 봐두는 것이 좋은 것 같다.

지금까지 Heap Overlapping에 관련된 공격들을 정리하면서 깨달은 점이 있다.
그건
전부 Chunk 구조체의 SIZE 필드를 조작하므로써 공격을 한다는 것이었다.
PREV_SIZE라 던가, SIZE 필드라던가 chunk의 사이즈를 Allocator에게 솎여서 잘못된 할당과 해제를 유발하므로써 기존에 있던 chunk에 중첩되는 chunk를 만들게 하는 방식이었다.

그렇기에 최신 glibc에서는 PREV_SIZE 체크 라던가 SIZE 체크 부분이 추가되었고
이 부분을 우회하는 것을 최근 how2heap에서 본 기억이 난다.

무튼,

heap overlapping 2번째 분석을 시작하자!



(5개의 힙)


5개의 힙 영역을 할당한다.
malloc 사이즈는 1000으로 16진수로는 3E8이다.

뒷자리가 8인 것을 보면 눈치 채겠지만, off-by-one에 취약할 것이다.



(각 힙영역의 범위)


각 힙영역을 표시하기 위해 해당 영역에 문자들을 넣어주었다.



(문자 입력)


그 후 p4 영역을 free해준다.
왜 굳이 p4일까?
-> p4를 free해주면 top청크와 병합되지 않는다. 이유는 top청크와 인접한 p5가 존재하기 때문에 병합되지 않는다. 그리고 공격의 개략적인 시나리오를 말하자면 p1 청크에서 off-by-one으로 p2의 청크 사이즈를 조작할 것이고, p3의 영역을 포함하고 있는 중첩된 heap영역을 할당받는 것이 우리의 목적이다.

: 그렇기에 p4를 free해준 것이다.



(free)


p4를 free해준 후

p1을 이용해 p2의 청크 사이즈를 조작한다.



(청크 사이즈 조작)


조작한 사이즈는
p2 청크의 사이즈 + p3 청크의 사이즈 + PREV_IN_USE + sizeof(size_t)
조작할 사이즈는 p2와 p3를 합한 청크 사이즈로 만들 것이다.
뒤에 prev_in_use 값은 0x1 로써, 이전 청크가 사용중이라는 것을 알려주기 위해 설정한다. 그렇지 않으면 이전 청크와의 병합도 시도할 것이다.
sizeof 값이 더해지는 이유는 p2, p3의 헤더 크기를 추가해주는 것이다. 




(p2 free)


그 후 p2를 free해준다.
그렇게 되면 다음과 같은 일이 일어난다.
1. allocator는 p2를 free하려고 한다.
2. p2의 PREV_IN_USE 비트를 보니 이전 청크를 사용하는 군!
3. next chunk를 검사한다. (p2 주소 + p2의 사이즈 = p4) = next chunk는 p4
=> 왜 다음 청크가 p3이 아닌지? 방금 우리는 p2의 사이즈를 p2,p3을 합한 덩어리로 조작했다. 그렇기에 p2 주소 + (조작된)p2의 사이즈 = p4의 주소 이고 p4가 next chunk가 된다.
4. p4(next chunk)를 확인해보니, free 되어있네???
5. p4랑 병합해야지~, p2는 결론적으로 p2,p3,p4를 포함한 커다란 free chunk가 되버린다.

그 후 malloc을 통해 p3을 포함할만큼 커다란 영역을 할당받는다면?



(큰 영역 할당)


그렇게 되면 p3영역이 포함된 영역을 할당해준다.



(할당된 영역)


할당 된 영역을 보면 p6 사이에 p3영역이 들어있는 것을 확인 할 수 있다.

현재 p3에 들어있는 데이터



(p3의 데이터)


그 후 p6을 F로 1500 글자 채워준다.



(F로 채우기)


그렇게 되면 500자가 p3영역을 침범하게 되어 p3 데이터 앞부분이 F로 채워지게 된다.



(확인)


확인을 통해 p3가 중첩된 영역을 할당받은 것을 확인 할 수 있다.

'Vulnerability_Tech > About Heap' 카테고리의 다른 글

(how2heap) - overlapping_chunks  (0) 2018.02.22
(how2heap) - house of lore  (0) 2018.02.21
(how2heap) - poison null byte  (0) 2018.02.20
malloc의 사용가능 영역(HEAP)  (0) 2018.02.20
(how2heap) - house_of_spirit  (0) 2018.01.17
(* 참조 - https://sploitfun.wordpress.com/2015/02/11/syscalls-used-by-malloc/)


malloc은 메모리 할당을 위해 사용하는 함수이다. 그 내부에서는 실제로 메모리를 할당받기 위해 시스템콜을 사용한다.

두가지 brk와 mmap 시스템콜을 사용한다.


(malloc)


brk
: brk는 프로그램 break location을 증가시키므로써 메모리를 획득한다. 

brk 를 확인해보기 위해 아래와 같이 코드를 작성한다.


(brk 테스트)


코드에서 brk를 사용했는데, sbrk는 어떤 목적으로 사용하였을까?



(brk 메뉴얼)


brk 메뉴얼을 확인해보면, brk와 sbrk가 있다.

sbrk의 경우 인자 값으로 확장하고 싶은 사이즈를 적고, 리턴값으로는 확장되기 이전의 program break를 반환한다. 그렇기에 저 위의 코드 sbrk(0)를 사용하게 되면 확장 사이즈는 0이므로 program break의 변화는 없고, 이전(변화가 없으니 현재) break location을 알 수 있다.

실행한 결과를 확인해보자.



(brk 되기 전)


brk 되기 전 프로그램 Break Location의 주소이다.

실제 메모리 모습을 확인해보면


(메모리 모습(brk 전))


[heap] 영역의 끝이 프로그램 Break Location인 것을 확인 할 수 있다.

brk를 한 후 결과를 확인해본다.



(brk 후)


brk 후 프로그램 Break Location의 위치가 0x1000 늘어난 것을 확인 할 수 있다.

메모리 상황을 확인해보면


(메모리 (brk 후))


[heap]의 영역이 늘어난 것을 확인 할 수 있다.

마지막으로 brk를 원래 위치로 되돌리는 것 까지 확인해보자.


(원위치)



(메모리 상황)


brk를 이용해 다시 줄여보았다. 이로써 brk를 통해 메모리를 할당하는 방식을 알아보았다.

그 다음 방식은 mmap이다.
mmap
: mmap은 호출한 프로그램이 사용하고 있는 영역에 대해 메모리를 잡는 것이다. 

코드를 이용해 직접 확인해보자.



(테스트 코드)


mmap 되기 전 상황과 된 후 상황일 먼저 비교해볼 것이다.


(mmap 전)



(메모리 (mmap 전))


mmap 전 라이브러리 파일 영역이다.

그 후 mmap을 진행한다.



(mmap 실행)



(메모리 ( mmap 후))


기존에 있던 프로그램의 메모리 영역에 mmap을 통해 공간을 만든 것을 확인 할 수 있다.

munmap 후까지 확인해본다.



(munmap)



(메모리 ( munmap 후 ))


munmap 후 다시 프로그램에게 메모리가 반환되는 것을 확인 할 수 있었다.

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

(RootKit) Simple Rootkit  (0) 2018.04.12
(RootKit) LKM(Loadable Kernel Module)  (0) 2018.04.03
System Hacking - jmp (반복문)  (0) 2017.04.19
System Hacking - jmp (분기문)  (0) 2017.04.18
System Hacking - 어셈블리어(사칙연산)  (0) 2017.04.14
이번에 분석한 자료는 house_of_spirit이다.

house_of_spirit 공격의 목적은 malloc의 return 결과를 우리가 원하는 청크의 주소로 만드는 것이다.
즉, freelist에 우리가 원하는 위치의 주소가 들어갈 수 있게 하는 것이다.

이 공격을 사용할 수 있는 조건은
우리가 메모리 영역에 가짜 청크를 만들 수 있어야한다는 것이다.
가짜 청크를 2개 만들어주는데 연속적으로 있어야한다.
또, 그 가짜 청크 주소를 free 함수에 넘겨 줄 수 있어야한다.
* free하기 전 malloc 1번은 꼭 필요하다.

먼저 malloc을 해준다.



(malloc)


 이 이유에 대해서 이해가 잘 가지 않았었다.
하지만 주석처리하고 실행해보고 이해할 수 있었다. 뒤에 우리가 가짜 청크를 만들고 그 주소를 free 시킬 것인데, malloc 할당을 한번도 하지 않고 free를 했기 때문에 에러가 난다.
이것을 막기 위해 malloc을 한번 해준다. 1로 해준 것은 그 값이 어떤 값이어도 상관없고 다만, 이 자료에서는 fastbin의 freelist를 이용할 것이기 때문에 작은 값으로 설정한 것이다.

이제 free의 인자로 넘길 포인터 변수를 만들어준다.



(포인터 변수 생성)


a 변수에 우리가 만든 가짜 청크의 주소를 쓸것이다.

이제 가짜 청크의 영역이다. 이 자료에서는 stack영역에 가짜 청크를 만들어주었다.

stack영역에는 비교적 우리가 값을 적기 쉽기 때문에 stack영역에 가짜 청크를 만들어 준 것 같다.



(가짜 청크를 위한 메모리 공간 확보)


위에 __attribute__는 컴파일러에게 특정한 방향으로 컴파일을 해달라고 부탁하는 명령이다.
aligned 16에 의해 16바이트로 정렬되게 컴파일 시킨다. 
64비트에서 unsigned long long은 8바이트이고 16바이트보다 작기 때문에 저 명령을 안써도 상관 없었다. (자료에서는 적혀있었다. 앞으로 64비트 이상의 컴퓨터가 나오게 되면 저 명령어가 필요할 수도 있을 것이다.)

그 다음으로 가짜 청크를 만들어주는 작업이다.



(가짜 청크 생성)


위 설명을 요약하자면
이 자료에서는 fastbin을 쓸것이기 대문에 PREV_INUSE는 무시해도 되지만, 다른 flag비트는 문제가 된다는 말로 모든 flag를 0으로 세팅하였다.
그리고 malloc 구현에 있어서 내부 internal size로 반올림 되기 때문에 0x30~0x38크기의 malloc 결과의 청크 사이즈는 0x40이 될것이기 때문에 우리는 0x40으로 만들어 줄 것이고
다음에 우리가 malloc할 때 0x30으로 할당 받을 것이다라는 이야기이다.

이제 다음 청크를 만들어 줘야한다.

free시 청크 뒤에 있는 청크의 사이즈를 검사한다. 그렇기에 정상적인 사이즈를 넣어야한다.



(검사 조건)


검사 조건은 이렇다.

SIZE_SZ란



(SIZE_SZ)


INTERNAL_SIZE_T의 크기가 SIZE_SZ 이고,
INTERNAL_SIZE_T는 size_t이다.
64비트에서는 8바이트 이므로 16바이트(0x10)보다 커야한다는 것이다.
당연한 것이, 청크의 헤더가 0x10이기 때문에 이거보다는 커야한다.

그 다음 조건은

av->system_mem 보다 작아야한다는 것




(system_mem)


av란 mstate로 정의 되어있고, mstate는 malloc_state 구조체이다.

이 구조체에 있는 system_mem은 할당된 메모리라고 나온다.
이 아레나가 할당된 크기를 말한다. 즉, 당연히 이 크기보다는 작아야한다는 것이다.

이런 아주 지극히 정상적인 크기의 값만 넣어주면 어떤 값이든 상관없다.

이 자료에서는 0x1234라는 값을 넣어주었다.



(두번째 청크 크기 설정)


여기서 배열 인덱스 9번에 적어주었는데, 그 이유는
우리가 첫번째 잡은 청크가 0x40의 크기였고 unsinged long long 크기가 8바이트 이기 때문에 총 배열 8개를 잡아먹고 그 다음 위치가 9이기 때문이다.

이제 우리가 만든 스택영역에 가짜 청크 두개를 만들었다.

이제 이 주소를 free 시키기 위해 포인터 변수에 이 주소를 먼저 넣어야한다.



(주소 입력)


인덱스가 2인 이유는 처음 0, 1은 헤더이다. free시킬 때는 user data영역의 주소를 가지고 free시키기 때문이다.

그 후 free 해준다.



(free)


그렇게 되면 지금 fastbin의 0x40의 리스트에 우리가 만든 가짜 청크의 주소 a의 주소가 들어있다.

이제 다시 malloc(0x30)을 하면 fastbin리스트에서 0x40의 주소를 찾아가 현재 있는 a의 주소를 return하게 되는 것이다.



(malloc)


공격 결과를 확인해보면 다음과 같다.



(공격 성공)

'Vulnerability_Tech > About Heap' 카테고리의 다른 글

(how2heap) - poison null byte  (0) 2018.02.20
malloc의 사용가능 영역(HEAP)  (0) 2018.02.20
(how2heap) - unsafe_unlink  (0) 2018.01.13
(how2heap) - fastbin_dup_into_stack  (0) 2018.01.11
(how2heap) - fastbin_dup  (0) 2018.01.04


정말 오래(?) 걸렸던 문제이다.

하루종일 문제푼것은 아니지만 조금씩 풀었는데 그래서그런지 오래걸린 문제이다.



(dragon 문제)




(문제화면)


문제 화면을 보면 게임을 준다.

게임을 다운로드해서 실행해본다.




(dragon 게임 실행)



직업을 고르고 용과 싸우는 게임이다.
이길 수 없다...

gdb로 분석을 시작했다.
main 함수에는 입출력 버퍼 설정하고 PlayGame 함수로 넘어간다.

그러므로 PlayGame 함수부터 분석해보겠다.



(PlayGame 함수)



함수를 보니 SecretLevel 함수?가 있다.
직업을 고를 때 3을 입력하면 이 함수로 넘어갈 수 있다.

그러면 SecretLevel에서는 뭘 할까?


(SecretLevel 함수)


비밀번호?를 입력 받고 문자열과 비교해서 일치하면 쉘을 던져준다...!

그래서 입력 문자열포멧과 비밀번호를 확인해보니



(입력 포멧, 입력해야할 문자열)



scanf 로 10글자를 받는데,,,
입력해야할 글자는 10글자가 훨씬 넘는다

즉 불가능.! 이다.
(그러면 저 문자열 10번째 다음 바이트를 00으로 바꿔서 해보자라는 생각이 들었는데, 저 문자열은 코드영역에 있기 때문에 쓰기 권한이 없어 불가능했다..)

그러므로 우리가 쓸수있는 방법은 바로 이 system("/bin/sh") 이 실행되도록 0x08048dbf 이 주소로 실행 흐름을 돌리면 된다.



(우리가 사용할 쉘)



여기서 이제 함수 하나하나 분석을 하는데 오래걸렸다...

FightDragon함수를 보면 malloc과 free를 2번씩 사용하는 모습을 확인하고 uaf 취약점이 아닐까 생각이 들었다.

그런데 uaf 취약점이든 bof든 무슨 취약점이든 입력할 곳이 있어야하는거 아닌가?...
전부 scanf  %d 로 입력을 받고 우리가 뭐 어떤 값을 입력할 곳이 없는 것이다

그러던 중 FightDragon 함수 아래쪽에서 문제 해결의 핵심을 찾았다.



(문제의 핵심)



이 부분의 scanf는 조금 특별했다.

위에서 malloc을 해주고 그 곳에 입력을 받고 게다가!



(16글자)



더구나 16글자를 입력 받는다!!!
이 부분에서 우리의 payload를 넣을 수 있다는 생각이 들었다.

그러면 어떻게 해야하나 위로 올라가보니



(공격함수)



공격함수 끝난 후 eax 값을 ebp-0x18을 넣고



(비교)



ebp-0x18 값이 0이 아니어야 입력할 기회가 주어진다.

즉, 용을 잡아야 기회가 주어진다.

또 여기서 시간을 많이 썼다.
용을 어떻게 잡는담... 인터넷에서 힌트를 좀 받았다. dragon 구조체를 잘 보면 된다고 나왔다.

dragon 구조체를 몇일을 들여다 보다 무릎을 탁 쳤다.




(dragon 구조체)



dragon 구조체를 보면
처음에는 몬스터 정보를 출력하는 함수 주소.
두번째는 몬스터 체력과 그 옆에 5가 체력회복량이다.
여기서 잘 보면 몬스터 체력이 바이트 단위로 설정되어있다. C언어로 표현하면 char자료형 처럼 1바이트 짜리이다.
범위로는 -127~127 이다.

엄마용이 80체력에 공격력이 10이니깐 계속 공격안하고 버티면 127을 넘길수 있을거 같다.
그러면 음수 값이 되고 용이 죽는다?

테스트!


(테스트 성공)



정말 127이 넘으니 용이 죽었다.
그리고 16바이트 입력을 넣을 수 있는 기회가 주어졌다.

그러면 취약점은?
scanf 로 입력받고 아래 코드를 보니 call eax 가 보인다.

보니 dragon 구조체가 free 된걸 까먹은건지 dragon 구조체의 첫번째 인자인 몬스터정보 출력 함수를 호출하고 있다.



(취약점)



내가 16바이트 입력한 곳이 방금 malloc 으로 받은 곳이니 이 주소가 전에 free 되었던 힙영역 주소이다.
같은 크기의 메모리 할당이니 전에 사용했던 그 주소가 재사용 된다.
확인해보자.! 
이름을 AAAA로 입력하였다. 그러면 처음 4바이트가 0x41414141 가 될것이고 아래 call eax에서

이 주소를 몬스터정보 출력 함수인줄 알고 이 주소를 호출하려 할 것이다.


(테스트)



AAAA 입력!




(확인)


테스트가 확인되었다.

그렇다면? 입력을 해줄 때 아까 우리가 봤던 SecretLevel에서의 쉘을 실행시키는 부분 주소를 입력해주면 된다.

pwn 모듈을 이용해 작성했다.



(exploit)



그리고 공격!



(쉘획득)



쉘을 획득하였다.!

'WarGame > 500 Project' 카테고리의 다른 글

(61/500) NOE.systems - double_input  (0) 2017.09.17
(60/500) pwnable.kr - crypto1  (0) 2017.08.27
(58/500) pwnable.kr - fsb  (0) 2017.08.12
(57/500) pwnable.kr - ascii_easy  (2) 2017.08.09
(56/500) pwnable.kr - asm  (0) 2017.07.14

+ Recent posts