1번을 선택하여 원하는 인덱스에 malloc으로 content를 삽입 가능하다. 또한 2번으로 원하는 인덱스를 free한다
3) 코드흐름 파악
Malloc()
main()은 별게 없고 Malloc함수와 Free함수만 집중적으로 보면 된다. 우선 어떤 인덱스에 넣을건지 선택하게 되는데 인덱스는 0 ~ 4 까지만 선택 가능하다. 또한 content의 size도 128byte까지만 입력 가능하다.
두개의 조건을 통과하면 bss 영역에 있는 ptr 배열에 입력한 사이즈만큼 malloc한 주소를 저장한다.
read 함수로 해당 영역에 content를 입력한다
Free()
여기도 선택하는 인덱스의 제한이 동일하게 존재한다.
0 ~ 4 사이의 인덱스를 선택했다면 해당 인덱스에 들어있는 청크를 free시킨다
2. 접근방법
우선 free시 해당 ptr 배열을 초기화 하지 않기 떄문에 uaf가 가능할 것이고 이를 통해 DFB가 가능하다.
그다음 libc 주소를 leak해야 한다. 입력한 데이터를 출력해주는 함수가 없는데 어떻게 해야 할까처음 알게된 방법이라 롸업을 보면서 문제를 풀었다. 일단 우리는 _IO_stdout_을 이용해서 leak을 할 것이다. leak 방법은 아래에서 확인 가능하다stdout의 file structure flag를 이용한 libc leak
처음에 문제를 풀때 128바이트보다 큰 값은 입력할 수 없기 때문에 128도 안됀다고 착각해버렸다. 따라서 fastbin 사이즈 청크만 할당 가능하다고 생각하여 unsorted bin에 청크를 넣는 것 부터 시작하였다.
시나리오
DFB를 이용하여 사이즈가 조작된 fastbin size 보다 큰 fake 청크를 fastbin에서 할당받게 만듬
fake 청크를 할당받았다면, 해당 청크가 free될 시 unsorted bin으로 들어감
따라서 fake 청크의 fd와 bk에 bin 주소가 들어가게 됨(main_arena+88)
bin은 main_arena 구조체에 들어있는 값임. main_arena는 libc의 data segment에 존재하기 때문에 결국 fd,bk에 들어가는 값은 libc 주소들과 가까움
stdout주소와 main_arena+88 주소는 하위 2바이트만 다르고 나머지는 동일함.
또한 오프셋을 동일하므로 가령 stdout의 오프셋이 0x620이면 0x?620 이렇게 2바이트 중 ?부분만 램덤으로 때려맞추면 됨.
그럼 이제 DFB를 다시 이용하여 main_arena+88 값을 조작한 뒤, 해당 청크를 할당받게 함
단. 그대로 stdout 주소로 박으면 안됨. 청크 구조 형태를 맞춰줘야하기 때문에
stdout-0x43 정도의 메모리를 보면 청크 구조처럼 되어있눈 부분이 있음. 이 주소를 main_arena+88 를 이용하여 조작해야함
이를 이용하여 libc leak을 진행
leak된 주소를 이용하여 malloc_hook을 one_gadget으로 덮음
DFB를 이용해서 똑같이 이용하면 됨.
malloc_hook 역시 청크 구조에 맞는 위치를 할당해줘야함.
malloc_hook이 덮혔다면 마지막으로 malloc 호출하면 쉘이 떨어짐
이제 위 시나리오대로 차근차근 확인해보자
3. 풀이
(중간중간에 디버깅을 종료하고 다시 시작해서 메모리 주소가 다름. 오프셋 위주로 확인하시길 ...)
DFB를 이용하여 사이즈가 조작된 fastbin size 보다 큰 fake 청크를 fastbin에서 할당받게 만듬
우선 3개의 malloc을 진행하고 인덱스 0, 1, 0 순으로 free시켜 DFB를 일으킨다.
첫번째 malloc 시에 마지막에 0x71이 들어가게 해준다
현재 fastbin 상태이다. 위에서 malloc한 동일 사이즈로 다시 malloc을 하게 되면 fastbin[5]에 들어있는 청크들이 재할당 된다.
DFB를 이용했기 때문에 처음 할당받은 0x2325000 청크를 처음에 할당받으면서 데이터를 쓰면, 삽입한 데이터가 3번째 malloc 시 청크 주소로 되면서 재할당 된다
다시 동일 사이즈로 4번의 malloc 중 첫번째 malloc이 호출된 상태이다. mem 영역에 한바이트는 0x60으로 넣었기 때문에 fastbin[5]의 마지막 리스트에는 0x176d060의 주소를 가리키게 된다.
따라서 2,3번이 진행되고 4번의 malloc이 진행된다면 0x176d060의 주소를 청크로하여 할당받을 것이다.
그렇게 된다면 해당 fake 청크의 mem 영역은 0x176d070부터 시작할 것이고, 0x176d078에 들어있는 0x71 값을 변경 가능하다. unsorted bin에 들어가게 하기 위해 0x91로 변경할 것이다.
4번까지 진행이 완료된 상황이다. ptr[1]을 보면 실사이즈는 0x71이지만 아까 0x91를 조작하여 넣었기 때문에 chunk size의 위치에 0x91이 들어가 있다. 따라서 해당 ptr[1]을 free시키면 0x91사이즈 청크로 착각하여 fastbin이 아닌, unsorted bin에 들어 갈 것이다.
fake 청크를 할당받았다면, 해당 청크가 free될 시 unsorted bin으로 들어감
따라서 fake 청크의 fd와 bk에 bin 주소가 들어가게 됨(main_arena+88)
bin은 main_arena 구조체에 들어있는 값임. main_arena는 libc의 data segment에 존재하기 때문에 결국 fd,bk에 들어가는 값은 libc 주소들과 가까움
stdout주소와 main_arena+88 주소는 하위 2바이트만 다르고 나머지는 동일함.
또한 오프셋을 동일하므로 가령 stdout의 오프셋이 0x620이면 0x?620 이렇게 2바이트 중 ?부분만 램덤으로 때려맞추면 됨.
헌데 free(1)이 진행되면 에러가남. 그이유는 다음과 같음
ptr[1]의 청크 사이즈는 현재 0x91로 파악하여 free가 된다면 top 청크가 바로나와야 하는데 현재 fake 청크이므로 top 청크 사이에 공백이 존재하게 된다
따라서 free(1) 시 에러가 발생하는 것임. 그렇기 때문에 에러를 피하기 위해 빨간색 영역을 청크의 영역으로 채워야함. 사이즈는 0x50임