다양한 기록

[모의 해킹] UAF & Double Free 본문

보안개론

[모의 해킹] UAF & Double Free

라구넹 2024. 12. 29. 22:21

1. UAF

 

 Use After Free 동적 할당과 관련하여 나타난다. 그대로, malloc() 같은 함수로 할당해줬던 메모리를 free() 반환한 다음에 메모리에 접근하는 경우 발생한다. CWE-416 속하는데, 메모리를 해제한 이후에 참조하여 프로그램이 크래시되거나, 예상치 못한 값을 이용하게 되거나, 어떠한 코드의 실행을 야기시킬 있다. 실제로 코드를 작성해서 테스트해보면 이미 free 메모리에 접근이 가능하다. 예를 들어, 이분 검색 트리에서 루트가 가리키는 값을 삭제하고자 했을 , free 하면 루트가 가리키는 포인터는 그대로라 문제가 발생할 있다. root = NULL; 같이 포인터가 가리키지 않도록 처리해야 의도된 결과를 얻을 있다. free 메모리의 처리를 제대로 하지 않으면, 문제가 발생할 있다. 다시 이분 검색 트리의 예시를 들자면, 트리의 값이 전부 삭제되었다고 해도, 루트가 가리키는 포인터를 없애지 않으면 루트는 어떠한 값을 가리키고 있게 된다. 트리가 비어 있으면 접근 가능한 노드가 없어야 하는데, 노드는 이미 프리된 노드를 가리키고 있으니 예상하지 못한 결과를 가져오게 된다.

 

프리 이후 해당 메모리에 대해 참조 가능한 포인터가 남아 있으면 데이터 손상의 위험성이 있다. 프리된 메모리는 빈에서 관리되는데, 다시 할당 요청이 오면 빈에서 꺼내서 관리하다가 꺼내서 준다. 문제는 빈에서 꺼내서 메모리 주소는 이전에 프리되었던 주소이기에, 전에 참조하고 있던 포인터가 새로 할당받은 값을 오염시킬 있다는 것이다.

 

실제로 코드를 작성하면 다음과 같이 나타난다.

a 프리하고 b 할당받으니, 프리된 a 주소를 b 할당받게 모습을 있었다.

 

그리고 free되기 사용했던 a 포인터가 가리키는 값을 변경하니, 새로 할당받은 b 가리키는 값까지 변경되는 것을 확인할 있다. 이런 식으로 원하지 않는 방향으로 손상될 있다.

 

또한, 단순히 데이터의 손상만을 일으키는 것이 아니라, 어떠한 함수가 작동되도록 하는 또한 가능하다. 다음이 예시이다.

 

함수를 실행시키는 부분은 (*func1)() (*func2)() 부분이다. 결과 Hello / World 출력되어야 하는데, 이미 프리된 메모리에 접근해서 값을 바꾸니 func2 가리키는 함수가 달라지는 것을 확인할 있다. 결과, Hello / Hello 출력되었다. 이를 공격자가 악용하기로 마음먹고 공격한다면 굉장히 악영향이 있을 있다. 함부로 실행되면 안되는 함수를 실행시킬 수도 있을 것이다. 그리고, 이번 과제가 이를 이용하여 플래그를 출력하는 함수를 실행하는 것이다.

 

2. Double Free

 

이름처럼 어떠한 메모리를 프리하게 되면 생기는 버그이다. CWE-415 해당하며, 프로그램이 동일한 인자로 free() 호출하면 프로그램의 메모리 관리 데이터 구조가 손상된다. 이렇게 데이터 구조가 손상됨에 따라, malloc() 통해 동일한 주소를 여러 반환해 있게 되고, 공격자들은 여러 할당된 메모리를 악용할 있다.

 

힙에서 해제된 메모리 청크를 관리하기 위해서는 빈을 사용한다. malloc() 메모리를 청크 단위로 할당해주고, free 사용이 끝난 메모리를 해제시키는데, 이때 해제된 메모리는 Last In First Out 방식으로 bin 매달리게 된다. 청크에서 포워드 포인터가 자신보다 먼저 해제되었던 청크를 가리키고, 포인터는 자신 이후에 들어온 포인터를 가리키게 된다. 이러한 링크드 리스트 형태로 관리되는 자료구조, 빈에 똑같은 청크가 여러번 들어오면 포워드 포인터와 백워드 포인터가 가리키는 방향이 꼬이게 되고, 결과적으로 자료구조가 꼬여 같은 청크를 여러 할당해주게 된다.

 

더블 프리에 의해 발생할 있는 상황을 간단히 표현하면 다음과 같이 나타낼 있다.

구체적인 형태는 구현에 따라 다르겠으나, 헤드와 포워드 포인터가 있는 서큘러 싱글 링크드 리스트 형태라 하면 더블 프리 발생 이미지와 같이 빈의 자료구조가 뒤틀리게 된다. 일반적인 상황에서는 빈에서 a 뽑아서 쓰면 a 가리키던 fd 헤드를 가리키게 되면서 빈이 비었다는 것을 나타나게 되는데, 더블 프리 버그가 발생하면 a fd 자기 자신을 가리키게 되며 메모리 할당 요청이 있으면 계속해서 a 할당해주게 된다.

 

보통 더블 프리를 방지하기 위해 같은 청크가 연속으로 들어오는 것은 못하도록 막아 둔다. 그래서 우회하기 위해 a > b > a 순서로 프리하기도 한다. 경우에는 다음과 같은 형태를 보이게 된다.

경우엔 a b 연속적으로 할당 받아지는 형태가 되어, 역시 정상적인 상태가 아니다.

 

같은 메모리 주소를 여러 할당하면 당연히 여러 문제가 발생한다. a b 있을 , a 가리키는 주소의 내용을 바꾸면 b 가리키는 주소의 내용도 자연스레 바뀌어버린다. 이러한 상황은 의도하지 않은 결과를 유발하며, 프로그램의 크래시와 같은 치명적인 결과를 유발할 있다.


공격

 

위와 같이 입력이 가능하고, 플래그를 출력하는 함수를 노려야 함

* 실습을 위해 취약한 메모리 할당 해제가 이루어진다

 

bin Chunk1 가리키고, Chunk1 fd NULL 가리킨다. 이때, 더블 프리가 발생하면 다음과 같은 구조가 된다.

 

Chunk1이 반복된다

 

그리고 노트를 작성하면(청크를 할당받으면), 작성한 노트의 값으로 청크 안에 있던 Chunk1 fd 값까지 변경된다. 이러면 앞으로 할당 받으면 노트에 작성했던 값으로 할당하게 것이다.

 

이미지에서 한번 할당한 후에 이런 상태가 것이고, 다시 할당하면 ????? 값이 할당하는 데에 쓰이게 된다. 이때 ????? 값이 print_flag 함수의 주소가 된다면, 이를 실행하는 것으로 플래그를 얻을 있을 것이다.

 

공격 코드

 

1 0 11 / 2 0 / 2 0 / 1 2 0x401275 / 1 4 44 / 1 6 0 / 4 6 / 3 6

a        / b    / c     / d                      / e          / f        /g     / h

부분을 나누어 설명할 있다

 

a : 1 0 11

더블 프리를 하기 위해선 일단 할당을 받아야 한다. 이를 위해 아무거나 할당받아 아무 입력이나 하면 된다.

 

b : 2 0, c : 2 0

더블 프리 버그가 발생하는 부분이다. 0 노트에 받았던 할당을 해제한다. 이를 통해 bin a에서 할당받았던 청크가 연속으로 들어가게 된다.

 

d: 1 2 0x401275

  부분에서 노트를 0x401275 작성하게 되면서, bin 안에 있는 청크의 fd 같이 바뀌게 된다. 이때, 0x401275인데 0x40127d 넣어도 플래그 출력 자체에는 문제가 없다.

 

e : 1 4 44

print_flag 주소를 할당받기에는 아직 청크에서 하나 빼내야 하니 아무거나 할당 받아준다.

 

f : 1 6 0

이제 할당 받은 것이 print_flag 주소이다. 이떄, 노트에 쓰는 값은 0이어야 한다. 이유는 다음 코드 때문이다.

write_note()에서 쓰려고 하는 값이 0이면 그냥 리턴하는데, 그게 아니면 작성한다. 만약 이때 0 아닌 다른 쓰려고 하면 함수 주소에 값을 쓰려고 하니 에러가 발생하며 종료된다.

 

 

g : 4 6

실행 , 마지막 확인으로 받아온 값이 print_flag 주소가 맞는지 체크한다.

 

h : 3 6

print_flag 함수를 실행한다.

'보안개론' 카테고리의 다른 글

[모의 해킹] 파라미터 위변조  (0) 2024.12.29
[모의 해킹] XSS  (0) 2024.12.29
[모의 해킹] Blind SQL Injection  (0) 2024.12.29
암호 기법 정리  (0) 2024.06.08
PT, BBP  (0) 2024.06.08