Unsorted Bin Attack
기본 정보
정렬되지 않은 리스트는 청크의 bk
주소에 unsorted_chunks (av)
의 주소를 쓸 수 있습니다. 따라서, 공격자가 정렬되지 않은 리스트 내부의 청크에서 bk
포인터의 주소를 수정할 수 있다면, 임의의 주소에 해당 주소를 쓸 수 있어 Glibc 주소를 노출하거나 일부 방어를 우회하는 데 도움이 될 수 있습니다.
따라서, 기본적으로 이 공격은 임의의 주소에 큰 숫자를 설정하는 것을 허용합니다. 이 큰 숫자는 힙 주소 또는 Glibc 주소일 수 있습니다. 전형적인 대상은 **global_max_fast
**이며, 이를 통해 더 큰 크기의 빠른 bin bin을 생성할 수 있게 됩니다 (정렬되지 않은 bin 공격에서 빠른 bin 공격으로 전환).
https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle에서 제공된 예제를 확인하고 0x400과 0x500 대신 0x4000과 0x5000을 사용하여 (Tcache를 피하기 위해) 현재 오류 **malloc(): unsorted double linked list corrupted
**가 트리거되는 것을 볼 수 있습니다.
따라서, 이제 이 정렬되지 않은 bin 공격은 (다른 확인 사항과 함께) 또한 이중 연결 리스트를 수정할 수 있어야 하므로 이것이 우회되어야 합니다 victim->bk->fd == victim
또는 victim->fd == av (arena)
, 즉 쓰고자 하는 주소가 가짜 청크의 fd
위치에 있어야 하고 가짜 청크 fd
가 아레나를 가리켜야 합니다.
이 공격은 정렬되지 않은 bin을 손상시킵니다 (따라서 작은 bin과 큰 bin도 손상됨). 따라서 이제 이제 빠른 bin에서 할당만 사용할 수 있습니다 (더 복잡한 프로그램은 다른 할당을 수행하고 충돌할 수 있음) 및 이를 트리거하려면 동일한 크기로 할당해야 합니다.
**global_max_fast
**를 덮어쓰면 빠른 bin에서 모든 다른 할당을 처리할 수 있을 것이라는 믿음을 가지고 이를 완료할 때까지 이를 활용할 수 있습니다.
guyinatuxedo의 코드는 이를 매우 잘 설명합니다. 그러나 malloc을 수정하여 Tcache에 끝나지 않도록 충분히 큰 메모리를 할당하면 이전에 언급한 오류가 발생하여 이 기술을 방지할 수 있음을 알 수 있습니다: malloc(): unsorted double linked list corrupted
Unsorted Bin Infoleak Attack
이것은 실제로 매우 기본적인 개념입니다. 정렬되지 않은 bin의 청크에는 포인터가 있습니다. 정렬되지 않은 bin의 첫 번째 청크는 실제로 fd
및 bk
링크가 **메인 아레나 (Glibc)**의 일부를 가리킵니다.
따라서, 청크를 정렬되지 않은 bin에 넣고 읽을 수 있다면 (사용 후 해제) 또는 적어도 1개의 포인터를 덮어쓰지 않고 다시 할당하여 읽을 수 있다면, Glibc 정보 누출을 얻을 수 있습니다.
이 글에서 사용된 공격은 4개의 청크 구조 (A, B, C 및 D - D는 상단 청크와의 통합을 방지하기 위한 것)를 남용하여 B에서 널 바이트 오버플로우를 사용하여 C가 B가 사용되지 않았음을 나타내도록 만들었습니다. 또한, B에서 prev_size
데이터가 수정되어 B의 크기가 B의 크기가 아닌 A+B가 되도록 했습니다.
그런 다음 C가 해제되고 A+B와 통합되었지만 B는 여전히 사용 중이었습니다. 크기 A의 새로운 청크가 할당되었고 그런 다음 libc 유출 주소가 B로 쓰여 유출되었습니다.
참고 및 다른 예제
글로벌 변수를 4869보다 큰 값으로 덮어쓰기 위한 목표이며 PIE가 활성화되지 않았습니다.
임의의 크기의 청크를 생성하고 원하는 크기의 힙 오버플로우가 있습니다.
공격은 3개의 청크를 생성하여 시작됩니다: 오버플로우를 남용하기 위한 청크0, 오버플로우를 받을 청크1 및 상단 청크가 이전 청크와 통합되지 않도록 하는 청크2.
그런 다음, 청크1이 해제되고 청크0이 오버플로우되어
bk
포인터가bk = magic - 0x10
를 가리키도록 합니다.그런 다음, 청크3이 청크1과 동일한 크기로 할당되어 정렬되지 않은 bin 공격을 트리거하고 글로벌 변수의 값을 수정하여 플래그를 획득할 수 있게 합니다.
병합 함수는 두 인덱스가 동일한 경우 다시 할당하고 그 후에 해제하지만 그 해제된 영역을 가리키는 포인터를 반환하여 사용할 수 있습니다.
따라서, 2개의 청크가 생성됩니다: 자신과 병합될 청크0 및 상단 청크와 통합되지 않도록 하기 위한 청크1. 그런 다음, 청크0을 두 번 병합하는 merge 함수가 호출되어 사용 후 해제가 발생합니다.
그런 다음,
view
함수가 사용 후 해제된 청크의 인덱스 2로 호출되어 libc 주소를 노출합니다.바이너리가 **
global_max_fast
**보다 큰 크기의 malloc만 허용하는 보호를 가지고 있기 때문에 fastbin을 사용하지 않으므로 정렬되지 않은 bin 공격이 사용되어 global 변수global_max_fast
를 덮어쓸 수 있습니다.그런 다음, 사용 후 해제 포인터인 인덱스 2로 edit 함수를 호출하여
bk
포인터를p64(global_max_fast-0x10)
을 가리키도록 덮어쓰고, 이전에 손상된 해제 주소(0x20)를 사용하여 정렬되지 않은 bin 공격을 트리거하여global_max_fast
를 덮어쓰고 이제 빠른 bin에서 청크를 생성할 수 있게 합니다.이제 빠른 bin 공격이 수행됩니다:
먼저
__free_hook
위치에 크기 200의 빠른 청크를 사용할 수 있다는 것을 발견합니다:
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gef➤ x/60gx 0x7ff1e9e607a8 - 0x59
0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200
0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
만약 이 위치에 크기가 0x200인 fast chunk를 얻을 수 있다면 실행될 함수 포인터를 덮어쓸 수 있습니다.
이를 위해 크기가
0xfc
인 새로운 청크가 생성되고 해당 포인터로 두 번 병합 함수가 호출되어 크기가0xfc*2 = 0x1f8
인 해제된 청크의 포인터를 fast bin에 얻을 수 있습니다.그런 다음, 이 청크에서
fd
주소를 이전__free_hook
함수를 가리키도록 수정하기 위해 편집 함수가 호출됩니다.그런 다음, 크기가
0x1f8
인 청크가 생성되어 fast bin에서 이전에 쓸모없는 청크를 검색하여 **__free_hook
**에 있는 fast bin 청크를 얻고system
함수의 주소로 덮어씁니다.마지막으로
/bin/sh\x00
문자열이 포함된 청크를 해제하기 위해 삭제 함수를 호출하여__free_hook
함수를 트리거하고/bin/sh\x00
을 매개변수로 사용합니다.언소트된 bin에서 청크를 통합하고 libc 정보 누출을 수행한 다음 malloc 후크를 원 갓젯 주소로 덮어쓰기 위해 fast bin 공격을 수행하는 또 다른 예제
크기가
0x100
보다 큰 청크만 할당할 수 있습니다.Unsorted Bin 공격을 사용하여
global_max_fast
를 덮어쓰기 (ASLR로 인해 1/16의 확률로 작동, 12비트를 수정해야 하지만 16비트를 수정해야 함).글로벌 배열의 청크를 수정하기 위한 Fast Bin 공격. 이를 통해 임의의 읽기/쓰기 기본 기능을 제공하여 GOT를 수정하고 일부 함수를
system
으로 지정할 수 있습니다.
Last updated