glibc-2.27
#1. 문제 살펴보기
처음보는 보호기법 3가지가 있다.
1. FORTIFY
SSP와 비슷하게 일반 메모리 버퍼에 대해 overflow를 감지하여 주는 역할을 한다.
(SSP : Stack Smashing Protector - Canary, ... )
2. ASAN : Address Sanitizer
google에서 제공하는 보호기법으로 아래에 해당하는 취약점을 방어한다고 한다.
- Use after free (dangling pointer dereference)
- Heap buffer overflow
- Stack buffer overflow
- Global buffer overflow
- Use after return
- Use after scope
- Initialization order bugs
- Memory leaks
https://www.lazenca.net/display/TEC/ASAN+-+Address+Sanitizer
https://github.com/google/sanitizers/wiki/AddressSanitizer
3. UBSAN : Undefined Behavior Sanitizer
- Shifts 연산오류 검출
- Signed Overflow
- NULL 포인터 접근 체크
- VLA (Variable Length Array) 검사 수행
- misaligned 메모리 액세스 검사
- nonnull attribute 변수에 null을 넣으려 할때
- 정의된 enum bound 를 벗어난 값을 저장하려고 할 때
http://m.blog.daum.net/tlos6733/181
#2. 문제 분석하기
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
const char *v3; // rdi
int v4; // eax
__int64 v5; // rdx
if ( *(_BYTE *)(((unsigned __int64)&stdin >> 3) + 0x7FFF8000) )
_asan_report_load8((unsigned __int64)&stdin);
setvbuf(stdin, 0LL, 2, 0LL);
if ( *(_BYTE *)(((unsigned __int64)&stdout >> 3) + 0x7FFF8000) )
_asan_report_load8((unsigned __int64)&stdout);
setvbuf(stdout, 0LL, 2, 0LL);
v3 = dword_78;
alarm(0x78u);
banner();
while ( 1 )
{
while ( 1 )
{
v4 = menu();
if ( v4 != 1 )
break;
add_note(v3, 0LL, v5, 0LL);
}
if ( v4 == 2 )
{
show_note(v3, 0LL, v5, 0LL);
}
else if ( v4 == 3 )
{
update_note(v3, 0LL, v5, 0LL);
}
else if ( v4 == 4 )
{
delete_note(v3, 0LL, v5, 0LL);
}
else
{
if ( v4 == 5 )
{
puts("Bye!");
_asan_handle_no_return();
exit(0);
}
if ( v4 == 666 )
{
secret(v3, 0LL, v5, 661LL);
}
else
{
v3 = "Error!";
puts("Error!");
}
}
}
}
코드들이 너무 길어서 숨겨놓겠다..!
1번 메뉴
unsigned __int64 add_note()
{
unsigned __int64 v0; // rdi
unsigned __int64 v1; // rax
unsigned __int64 v2; // rdi
__int64 v3; // rax
unsigned __int64 v4; // rdi
unsigned __int64 v5; // rcx
__int64 v6; // rcx
unsigned __int64 v7; // rdi
__int64 *v8; // rax
unsigned __int64 v9; // rdi
unsigned __int64 v10; // rdi
__int64 v12; // [rsp+8h] [rbp-28h]
int v13; // [rsp+18h] [rbp-18h]
int v14; // [rsp+1Ch] [rbp-14h]
int v15; // [rsp+20h] [rbp-10h]
int i; // [rsp+24h] [rbp-Ch]
v15 = -1;
for ( i = 0; i < 10; ++i )
{
v0 = (unsigned __int64)¬es + 8 * i;
if ( *(_BYTE *)((v0 >> 3) + 0x7FFF8000) )
_asan_report_load8(v0);
if ( !*(_QWORD *)v0 )
{
v15 = i;
break;
}
}
if ( v15 == -1 )
error();
printf((unsigned __int64)"Size: ");
v14 = read_int();
if ( v14 < 16 || v14 > 1024 )
error();
v12 = malloc((__asan *)v14);
if ( !v12 )
error();
printf((unsigned __int64)"Content: ");
v13 = read_until_nl_or_max(v12, v14 - 8);
printf((unsigned __int64)"ID: ");
v1 = read_ul();
v2 = v13 + v12;
if ( *(_BYTE *)((v2 >> 3) + 0x7FFF8000) )
v1 = _asan_report_store8(v2);
*(_QWORD *)v2 = v1;
v3 = malloc((__asan *)&word_10);
v4 = (unsigned __int64)¬es + 8 * v15;
if ( *(_BYTE *)((v4 >> 3) + 0x7FFF8000) )
v3 = _asan_report_store8(v4);
*(_QWORD *)v4 = v3;
v5 = (unsigned __int64)¬es + 8 * v15;
if ( *(_BYTE *)((v5 >> 3) + 0x7FFF8000) )
_asan_report_load8((unsigned __int64)¬es + 8 * v15);
if ( !*(_QWORD *)v5 )
error();
v6 = v12;
v7 = (unsigned __int64)¬es + 8 * v15;
if ( *(_BYTE *)((v7 >> 3) + 0x7FFF8000) )
_asan_report_load8(v7);
v8 = *(__int64 **)v7;
if ( *(_BYTE *)((*(_QWORD *)v7 >> 3) + 0x7FFF8000LL) )
v8 = (__int64 *)_asan_report_store8((unsigned __int64)v8);
*v8 = v6;
v9 = (unsigned __int64)¬es + 8 * v15;
if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
_asan_report_load8(v9);
v10 = *(_QWORD *)v9 + 8LL;
if ( *(_BYTE *)((v10 >> 3) + 0x7FFF8000) )
_asan_report_store8(v10);
*(_QWORD *)v10 = cfi_check;
puts("Add success!");
return __readfsqword(0x28u);
}
2번 메뉴
unsigned __int64 show_note()
{
unsigned __int64 v0; // rdi
unsigned __int64 v1; // rdi
__int64 v2; // rbx
unsigned __int64 v3; // rbx
unsigned __int64 v5; // [rsp+8h] [rbp-28h]
int v6; // [rsp+10h] [rbp-20h]
printf((unsigned __int64)"Index: ");
v6 = read_int();
if ( v6 < 0 || v6 >= 10 )
goto LABEL_20;
v0 = (unsigned __int64)¬es + 8 * v6;
if ( *(_BYTE *)((v0 >> 3) + 0x7FFF8000) )
_asan_report_load8(v0);
if ( !*(_QWORD *)v0 )
LABEL_20:
error();
v1 = (unsigned __int64)¬es + 8 * v6;
if ( *(_BYTE *)((v1 >> 3) + 0x7FFF8000) )
_asan_report_load8(v1);
v5 = *(_QWORD *)v1;
if ( *(_BYTE *)((*(_QWORD *)v1 >> 3) + 0x7FFF8000LL) )
_asan_report_load8(v5);
if ( *(_BYTE *)((v5 >> 3) + 0x7FFF8000) )
_asan_report_load8(v5);
v2 = *(_QWORD *)v5;
if ( *(_BYTE *)((v5 >> 3) + 0x7FFF8000) )
_asan_report_load8(v5);
v3 = strlen(*(_QWORD *)v5) + v2 + 1;
if ( *(_BYTE *)((v3 >> 3) + 0x7FFF8000) )
_asan_report_load8(v3);
printf((unsigned __int64)"Content: %s\nID: %lu\n");
return __readfsqword(0x28u);
}
3번 메뉴
unsigned __int64 update_note()
{
unsigned __int64 v0; // rdi
unsigned __int64 v1; // rdi
__int64 v2; // rbx
__int64 v3; // rsi
unsigned __int64 v4; // rax
unsigned __int64 v5; // rdi
__int64 (__fastcall **v6)(); // rdi
__int64 (__fastcall *v7)(); // rbx
unsigned __int64 v9; // [rsp+8h] [rbp-28h]
int v10; // [rsp+18h] [rbp-18h]
int v11; // [rsp+1Ch] [rbp-14h]
printf((unsigned __int64)"Index: ");
v11 = read_int();
if ( v11 < 0 || v11 >= 10 )
goto LABEL_29;
v0 = (unsigned __int64)¬es + 8 * v11;
if ( *(_BYTE *)((v0 >> 3) + 0x7FFF8000) )
_asan_report_load8(v0);
if ( !*(_QWORD *)v0 )
LABEL_29:
error();
v1 = (unsigned __int64)¬es + 8 * v11;
if ( *(_BYTE *)((v1 >> 3) + 0x7FFF8000) )
_asan_report_load8(v1);
v9 = *(_QWORD *)v1;
printf((unsigned __int64)"New Content: ");
if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
_asan_report_load8(v9);
v2 = *(_QWORD *)v9;
if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
_asan_report_load8(v9);
v3 = strlen(*(_QWORD *)v9) + 1;
v10 = read_until_nl_or_max(v2, v3);
printf((unsigned __int64)"New ID: ");
v4 = read_ul();
if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
v4 = _asan_report_load8(v9);
v5 = v10 + *(_QWORD *)v9;
if ( *(_BYTE *)((v5 >> 3) + 0x7FFF8000) )
v4 = _asan_report_store8(v5);
*(_QWORD *)v5 = v4;
v6 = (__int64 (__fastcall **)())(v9 + 8);
if ( *(_BYTE *)(((v9 + 8) >> 3) + 0x7FFF8000) )
_asan_report_load8((unsigned __int64)v6);
v7 = *v6;
if ( *v6 != cfi_check )
{
_asan_handle_no_return();
_ubsan_handle_cfi_check_fail_abort(&unk_34B100, v7);
}
((void (__fastcall *)(_QWORD))v7)((unsigned int)v11);
puts("Update success!");
if ( *(_BYTE *)((v9 >> 3) + 0x7FFF8000) )
_asan_report_load8(v9);
if ( *(_QWORD *)v9 >> 44 != 6LL )
error();
return __readfsqword(0x28u);
}
4번 메뉴
unsigned __int64 delete_note()
{
unsigned __int64 v0; // rdi
unsigned __int64 v1; // rdi
unsigned __int64 v2; // rdi
unsigned __int64 v3; // rdi
int v5; // [rsp+14h] [rbp-Ch]
printf((unsigned __int64)"Index: ");
v5 = read_int();
if ( v5 < 0 || v5 >= 10 )
goto LABEL_16;
v0 = (unsigned __int64)¬es + 8 * v5;
if ( *(_BYTE *)((v0 >> 3) + 0x7FFF8000) )
_asan_report_load8(v0);
if ( !*(_QWORD *)v0 )
LABEL_16:
error();
v1 = (unsigned __int64)¬es + 8 * v5;
if ( *(_BYTE *)((v1 >> 3) + 0x7FFF8000) )
_asan_report_load8(v1);
v2 = *(_QWORD *)v1;
if ( *(_BYTE *)((v2 >> 3) + 0x7FFF8000) )
_asan_report_load8(v2);
free(*(__sanitizer **)v2);
v3 = (unsigned __int64)¬es + 8 * v5;
if ( *(_BYTE *)((v3 >> 3) + 0x7FFF8000) )
_asan_report_load8(v3);
free(*(__sanitizer **)v3);
puts("Delete success!");
return __readfsqword(0x28u);
}
666번 메뉴
unsigned __int64 secret()
{
_BYTE *v0; // rax
unsigned __int64 v2; // [rsp+0h] [rbp-10h]
if ( secret_enable )
{
printf((unsigned __int64)"Lucky Number: ");
v2 = read_ul();
if ( v2 >> 44 )
v0 = (_BYTE *)(v2 | 0x700000000000LL);
else
v0 = (_BYTE *)v2;
*v0 = 0;
secret_enable = 0;
}
else
{
puts("No secret!");
}
return __readfsqword(0x28u);
}
그나마 빠르게 발견한 취약점은 UAF 이다.
간단히 메뉴의 기능들을 정리하자면 다음과 같다
1. add_note 노트 할당
2. show_note 작성한 내용 확인
3. update_note 노트 수정
4. delete_note 노트 삭제
5. exit 종료
666. seceret 특정한 값 입력
#3. 삽질
처음 접해본 것들을 모두 적어보았다.
간단하게 설명해보면 v0 >> 3 은 2진수로 표현된 v0의 값을 오른쪽으로 3칸 밀어낸다.
예) 40 (0010 1000) >> 3 의 결과는 5 (0000 0101) 이다.
디버깅이 되지 않으니 어떻게 해야할지 감이 오지 않는다..
정적분석을 통해서 문제를 풀어야하는 것일까?
메모리가 로드된 모습을 확인해보았다.
32bit 문제에서 나오던 스택주솟값이 들어가있다 (실행권한은 없다)
또한 heap영역이 할당되어있으나 heap 명령어를 통해 메모리를 확인해볼 수 가 없다
ASAN에 대해 공부를 마친 후에야 풀 수 있을 듯 하다.
2019.11.2 여기서 접다
#4. Exploit Code
'CTF Review' 카테고리의 다른 글
[ stack ] Rooters CTF 2019 baby_pwn (0) | 2019.11.13 |
---|---|
[ heap ] Backdoorctf 2019 babytcache (0) | 2019.11.06 |
[ stack ] BSidesSF 2019 CTF slowfire 미완성 (0) | 2019.11.04 |
[ heap ] HSCTF 2019 aria-writer-v3 (0) | 2019.10.07 |
[ stack ] NACTF 2019 bufover-1 (0) | 2019.10.03 |