#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
char *ptr[7];
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
}
void create_heap(int idx) {
size_t size;
if( idx >= 7 )
exit(0);
printf("Size: ");
scanf("%ld", &size);
ptr[idx] = malloc(size);
if(!ptr[idx])
exit(0);
printf("Data: ");
read(0, ptr[idx], size-1);
}
void modify_heap() {
size_t size, idx;
printf("idx: ");
scanf("%ld", &idx);
if( idx >= 7 )
exit(0);
printf("Size: ");
scanf("%ld", &size);
if( size > 0x10 )
exit(0);
printf("Data: ");
read(0, ptr[idx], size);
}
void delete_heap() {
size_t idx;
printf("idx: ");
scanf("%ld", &idx);
if( idx >= 7 )
exit(0);
if( !ptr[idx] )
exit(0);
free(ptr[idx]);
}
void get_shell() {
system("/bin/sh");
}
int main() {
int idx;
int i = 0;
initialize();
while(1) {
printf("1. Create heap\n");
printf("2. Modify heap\n");
printf("3. Delete heap\n");
printf("> ");
scanf("%d", &idx);
switch(idx) {
case 1:
create_heap(i);
i++;
break;
case 2:
modify_heap();
break;
case 3:
delete_heap();
break;
default:
break;
}
}
}
이전 문제와 보호 기법이 같다. 따라서 Got Overwrite 할 수 있고, 코드, 데이터 섹션이 고정되어 있다.
get_shell 함수도 존재해 특정 함수 got 값을 get_shell 주소로 덮어보자
삽질하기 전에 리모트 환경에 보호 기법이 존재하는지 확인해 보자
0번 index에 힙 영역을 할당받고 두 번 해제하는 코드이다.
프로그램이 종료되었다. 원래 double free 어쩌고 문구가 떠야 하지만 일부러 안 보이게 한 것 같다. 째든 tcache에 보호 기법이 적용되었다. 이를 우회해야지 tcache duplication이 가능하다.
코드를 보면 modify라는 함수에서 index와 size를 입력받고 size만큼 해당 index에 data를 넣을 수 있다.
이를 통해 free 된 청크 key 값을 바꾼 다음 free를 하면 보호 기법을 우회할 수 있다.
e -> key 위치는 fd 다음에 존재한다. 따라서 "A"*8 개로 fd 값을 덮고 "A"를 통해 e -> key 값 1byte를 "A"로 바뀌기 때문에 검증을 우회하여 free를 할 수 있게 된다. -> tcache duplication 발생!
프로그램이 종료되지 않는 걸 보면 보호 기법이 우회되었고 tcache duplication이 발생한 걸 알 수 있다.
이제 got를 get_shell 주소로 덮어보자
scanf got 값을 get_shell 주소로 덮었다.
로컬에서는 익스가 성공했다. 리모트 ㄱㄱ
[그림 1-8]은 리모트에서 시도한 것이다. 익스가 안된다....흠... 찾아보니까 일단 리모트 환경(20.04)이랑 로컬 환경(18.04) 우분투 버전이 다르다. 따라서 tc_idx라는 걸 신경 써야 된다고 한다. tc_idx는 bin에 들어간 청크의 개수 인다. 이 값이 0이면 tcache_bin에 청크가 없다는 뜻으로 tcache_bin을 참조하지 않는다고 한다.
직접 확인해보자
[그림 1-9]는 0번 index를 해제한 상태이다.
tcache_bin에 0번 index 청크가 들어가 있고 아래 숫자 1이 들어가 있다. 아래 숫자 1이 tcache_bin의 개수이다.
[그림 2-1]은 tcache duplication이 발생한 상태이다. tc_idx 개수는 2개이다.
하지만 got 값을 덮기 위해 총 세 번의 malloc을 시도하는데 tc_idx 개수는 2개이므로 마지막 create(0x40,p64(get_shell)) 코드는 우리가 원하는 데도 실행이 안되어 shell이 실행되지 않는다.
따라서 tc_idx를 3개로 맞춰줘야 한다. tc_idx 개수는 해제된 청크의 개수이므로 3번의 create를 하기 전 보호 기법을 우회해서 tc_idx 3으로 맞추자
c-d m-d m-d을 통해 tc_idx를 3개로 맞추었다.
성공!
알게 된 점
1. 라이브러리 버전이 다르다 -> 라이브러리 함수 동작이 바뀐다.
따라서 18.04에 없던 tc_idx 검증이 20.4에는 추가되어있다
2. 동일한 버전이라도 상세 버전에 따라 또 달라질 수 있다.
https://dreamhack.io/forum/qna/1305
https://dreamhack.io/forum/qna/3086
'Dreamhack - pwnable' 카테고리의 다른 글
cmd_center (0) | 2023.02.03 |
---|---|
sint (0) | 2023.02.03 |
tcache_dup (0) | 2023.02.01 |
tcache_poison (0) | 2023.01.30 |
uaf_overwrite (0) | 2023.01.28 |