atm_service Write-up
우선 보호기법을 먼저 확인해보니 FULL RELRO & CANARY에서 한숨이 나온다...
실행을 시켜보면, (1) ~ (3) 사이의 메뉴가 존재하여 각 메뉴들을 분석해보아야 할 것 같다
1번 메뉴 ( save_request)를 보면 , 입력하는 문자열에 대한 조건을 알 수 있다.
'ATM-REQ/1.0\n' 이 처음에 있어야 하며, 그 뒤에는 ' atm-ip' + '(ip정보)\n',
그리고 pin정보를 넣으려면 'mask-pin-at' + (pin 정보) 가 있어야 한다.
여기서, atoi(핀 정보)를 하여, 'ATM-REQ/1.0\n'이 적힌 위치부터 시작하여 pin정보만큼 떨어진 위치에
'*' 4개로 덮는 것이 가능하다.
2번 메뉴(send_saved_request)를 보면 inet_aton으로 ip정보를 확인 하는 조건문이 있고
그 내부에 memcpy()로 입력한 ip를 &dest에 복사하는 코드가 보인다.
memcpy()는 언제나 취약점을 만들어 내니 의심해볼만 하다.
memcpy()에서 취약점을 이용하기 위해 확인해보니, inet_aton ← 이 함수가 ip가 올바른지 검사할 때,
ip = '1.2.3.4' + ' '(space) + 'DATA~'로 해버리면 필터링이 걸리지 않았다. 즉, 사이에 공백만 추가해 주면 내가 원하는 정보를 모두 memcpy로 저장해버릴 수 있다는 말이다.
3번 메뉴는 저장해둔 정보를 출력해주는데 여기서 특이한 것은 ( is_pin ≠ 1 ) 일 때만 pin값을 출력해주는 것이었다. 여기서 출력되는 값은 (atoi_pointer)이다.
이는 이전에 1번 메뉴에서 이름을 바꿔둔 변수로, 숫자를 잘 입력하여 내가 원하는 값을 출력할 수 있어 보인다.
문제에서 libc정보를 주었으니 아마 이 출력을 이용해 libc leak를 하지 않을까라는 추측을 할 수 있다.
허나( is_pin ≠ 1 ) 일 때만 출력 되므로, 처음에 1번 메뉴를 이용해서 atoi_pointer에 원하는 값(libc_base 주소)을
저장해 두고, 다시 1번 메뉴를 사용하여 is_pin 을 0으로 만든 다음 3번 메뉴를 이용해서 출력하면 될 것으로 추측 가능하다.
이후, 쉘을 따려면 2번 메뉴에서 memcpy를 이용해서 BOF를 일으켜 ret을 조작하면 가능할 것인데,
여기서는 CANARY가 문제이다.
CANARY는 확인해보니, 각 스택에 쌓여 있지만 스택 뿐만 아니라 (전역변수?)의 위치에 들어있음을 알 수 있었고, 이 write권한이 있는 것을 확인할 수 있다. 아까, 원하는 위치에 ''을 넣을 수 있었는데 여기서 이 카나리 8바이트 전부를 ''로 덮어버린다면 우리는 카나리 값을 알기 때문에 BOF가 가능해진다.
또, ret을 원샷가젯으로 보내버리면, 쉘을 딸 수 있을 것이다.
< 시나리오 >
(1번 메뉴)로 atoi_pointer 위치에 (libc_base 주소) 저장 ⇒ 다시 (1번 메뉴)로 (is_pin = 0)으로 설정함
⇒ (3번 메뉴)로 libc_base leak ⇒ (1번 메뉴) 2번으로 카나리 모두 '*'로 덮음 ⇒ (2번 메뉴)로 BOF 일으켜
ret을 원샷가젯으로 보내버려서 쉘을 딴다.
우선, 시나리오대로 1번 메뉴로 들어와서, malloc을 call한 후, 반환하는 값을 통해
malloc에 의해 할당되는 주소를 알아낸다.
그리고 libc가 저장된 주소를 찾고, malloc에 의해 할당된 위치와의 거리를 구한다.
거리는 각각 0x3aff0 , 0x3b330이다.
하지만 우리는 총 4바이트만 읽을 수 있기 때문에 0x3aff1 , 0x3b331만큼 떨어진 위치의 4byte를 읽을 것이다.
(어차피 제일 첫 바이트는 \x7f이며, 마지막 바이트는 \x00이기 때문에 사이의 4바이트만 읽어도 libc leak 가능)
이제 남은건 canary를 덮는 일이다.
예전에 __readfsqword() ← 이게 카나리의 값을 불러와서 저장한다고 들었어서 , main 함수의 [rbp-8]에 Canary값이 저장되어 있음을 알 수 있었다.
아까 했던 것과 동일하게, malloc을 거쳐서 반환하는 주소를 확인하고, 그 주소와 Canary와의 거리를 계산하면
(1번 메뉴)를 2번 호출하여 Canary를 '****'로 덮을 수 있다.
우선 카나리가 저장된 주소 확인하고 ,
첫번째 1번메뉴로 4바이트 덮고,
두번째 1번메뉴를 통해 카나리 = '****'로 조작하였다.
이젠 그냥 2번 메뉴를 통해 카나리 위치에는 '*'로 잘 넣어주고 one_shot으로 ret 해주면, 쉘을 딸 수 있다.
'CTF > CTF_writeup' 카테고리의 다른 글
[zer0pts] diysig (0) | 2020.03.12 |
---|---|
[zer0pts] ROR (0) | 2020.03.12 |
[CODEGATE 2020 예선] Halffeed (0) | 2020.02.09 |
[Hack.lu CTF 2019] Chat (0) | 2020.02.09 |
[justCTF 2019] Shellcode Executor PRO Write-up (0) | 2020.02.09 |