티스토리 뷰

CTFs WriteUp

[pwn] 0ctf 2021 - listbook

sindo 2021. 7. 6. 00:00
0ctf 2021 - Listbook

Listbook

제공해준 libc 파일 버전은 GLIBC 2.31-0ubuntu9.2 이다.

Ubuntu 20.04에서 풀었다.

보호기법

 

 

메뉴로는 add, delete, show, exit 가 있는데 하나씩 살펴보자.

add

제일 먼저 코드를 보면 v2 변수에 0x20크기만큼 할당하는 것을 볼 수 있고, 아래에 입력되는 값들을 토대로 구조체를 생성해보면

처럼 지을 수 있겠다.

새로운 구조체를 적용시키고 다시 확인해보면

이렇게 된다.

 

흐름을 보면 [1] 에서 sub_134C(v2, 16) 작업을 한 뒤 반환값을 dword_4440의 index로 사용하여 값이 존재할 경우 qword_4840[v1]의 값을 v2->next에 넣는다.

만약 조건문을 통과하지 못하면 qword_4840[v1]에 v2를 집어넣고 dword_4440[v1]값을 1로 맞춘다.

 

v1의 값이 어떻게 나오는지 알아보기 위해 sub_134C를 분석해보자.

sub_134C

복잡해보이긴 한데, book->name을 가지고 연산을 진행해서 1byte를 만들어낸다.

연산을 통해 만들어낸 1byte가 qword_4840dword_4440의 index로 사용된다.

 

Show

show에서는 별거 없는데, 사용자가 입력한 값 v3가 있을 때 qword_4840[v3]dword_4440[v3]의 값이 0이 아닐 경우 해당 위치에 있는 book 연결 리스트들을 출력해준다.

 

이런 기능들이 있는 것을 보아 qword_4840book *자료형을 저장하는 hashtable임을 추측할 수 있다. 배열에 적혀있는 값은 각 hashtable의 head가 되고 같은 hash index에 대해 head->next 로 연결되어 있는 구조로 되어있다.

 

Delete

Delete를 진행할 때는 원하는 index에 qword_4840dword_4440 둘다 값이 0 이 아니라면 해당 hashtable을 전부 free시킨다.

 

Vulnerability

취약점은 add에서 사용하는 sub_134C 함수에서 발생한다.

해당 함수에서 마지막에 16으로 나머지만 챙기기 때문에 0~15 인덱스만 나올거 같이 보이지만, 실제로 일부 값에 대해서 -128 값이 나온다. 따라서 qword_4840[-128]을 참조하게 되고, 해당 위치는 dword_4440의 0, 1번째 index의 값을 덮을 수 있게 된다.

 

따라서 만약 dword_4440[0]free했을 때 위의 취약점을 트리거 시켜주면 heap의 주소가 dword_4440[0], dword_4440[1]에 적히기 때문에 다시 한 번 free가 가능하다. 따라서 Double Free 취약점이 발생한다.

 

상황을 메모리로 보자면,

현재 dword_4440의 배열이 위처럼 되어있다. 할당이 되어있을 때 dword_4440[n] = 1로 켜두는 식인데, 여기서 Delete(0)을 호출하면

이처럼 dword_4440[0] = 0으로 바뀌게 된다.

하지만 여기서 위에말한 OOB 취약점을 사용해서 hashtable[-128]에 heap을 할당받게 한다면

이런식으로 heap이 dword_4440 배열의 0, 1번째 칸을 덮어버린다. 따라서 다시한번 Delete(0)을 할 수 있고, 이는 Double Free로 이어진다.

 

물론 glibc 2.31 버전에선 보호기법 때문에 바로 free가 가능하지는 않다. 따라서 몇가지 트릭을 사용해서 tcache의 fd를 덮어줘야 한다.

 

나중에 Double Free를 트리거하기 위해서 Show(0)를 통해 먼저 libc leak을 진행한다. (heap leak은 name만 가득 채워주고 next하나더 생기면 leak된다.)

2.31 버전에서는 Free된 chunk가 tcache에 들어있는지 검사하는 방법을 통해 Double Free를 막기 때문에, Unsorted Bin이나 Small Bin을 사용해서 공격을 진행해야 한다.

따라서 다른 chunk를 적절히 free해서 tcache를 채우고 Double Free를 원하는 Chunk를 Unsorted bin에 옮긴 후 다른걸 다시 free하여 small bin으로 옮겨준다.

 

현재 Double Free할 chunk(2c0)가 smallbin에 들어가 있는 상태이다.

여기서 한번 free해주면

처럼 smallbin에 있는 chunk지만 free됨으로써 tcache로 이동하고, small bin이 와장창 깨진다.

이제 Freed Chunk가 tcache와 small bin 둘에 들어가 있으므로 트릭을 사용하면 된다.

 

현재 chunk는 아래처럼 구성되어 있다.

이 상태에서 2c0 chunk를 할당받게 되면 tcache가 먼저 사용되기 때문에 small bin의 2c0 chunk는 그대로 유지된다.

따라서 tcache를 사용하면서 동시에 fake chunk를 구성해준다.

위의 구조를 보면 380 chunk가 fake로 구성된 chunk이다. 물론 해당 chunk로부터 0x210떨어진 곳에도 prev_size라던지 값들을 전부 맞춰두었다.(add를 할 때 spray를 전부 해둠)

위의 구조를 보면 small bin에 있던 double free chunk의 fd를 0, bk를 fake chunk를 가리키도록 했고, fake chunk의 fd에는 original chunk의 주소, 그리고 bk에는 원래 small bin에 있을 당시(깨지기 전) bk 주소를 적어주었다.

지금 bins의 상태를 보면

이런식으로 되어 있다.

 

이 상태에서 unsorted bin에 있는 0x210 크기의 chunk를 할당하면

이런식으로 small bin의 애들이 전부 tcache bins로 이동하게 된다. 이 때 가장 마지막 tcache chunk는 우리가 적어줬던 fake chunk이다..!!

 

하지만 아직 문제가 있는 것이, glibc 버전이 업데이트 되면서 tcach bins cnt값이 0이면 free chunk가 있더라도 새로 할당을 해버린다. 그렇기 때문에 어떤 의미없는 chunk free 후 fake chunk를 free해서 cnt가 1이상의 값을 유지하도록 해주는 것이 중요하다.

 

다른 chunk를 먼저 free한 상태로 만드는 것은 어렵지 않고 , 이제 어떻게 쉘을 딸 것인지에 대해 알아야 하는데 원가젯은 전부 말을 듣지 않았다. 그래서 free_hook에 system을 적고 0x200 chunk에 /bin/sh를 적어줘서 free를 할 때 system("/bin/sh")을 호출할 수 있게 조작했다.

 

Exploit

 

Flag

 

'CTFs WriteUp' 카테고리의 다른 글

[pwn] UTCTF 2021 - monke  (0) 2021.03.23
[pwn] UTCTF 2021 - AEG  (0) 2021.03.19
[pwn] UTCTF 2021 - Functional Programming  (0) 2021.03.18
[pwn] UTCTF 2021 - 2Smol  (0) 2021.03.16
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
글 보관함