앞으로 글 제목 앞에 문제별로 [USE] [BOF] [FSB] 등등이 나뉘어져 붙을겁니다.
[USE] 는 이런 문제들을 가지고 나뉘어질것이며 BOF 와 FSB 는 말 안해도 아시죠?
IO 워게임을 Level1 부터 다시 풀이해가겠습니다.
기존에 올라와있던 워게임처럼 간단하게 올릴생각은 아니구요, 처음부터 모르는게 있으면 완벽하게 올리려고 합니다.
편하게 작성하는거라 말투는 수시로 바뀔겁니다 ㅋㅅㅋ
IO 워게임 공식 사이트 : http://io.smashthestack.org:84/
level1@io:~$ cd /levels
level1@io:/levels$ ./level01
Usage: ./level01 <password>
서버에 접속해 Level1 문제파일을 실행하면 다음과 같이 뜬다.
서버에 접속해 Level1 문제파일을 실행하면 다음과 같이 뜬다.
level1@io:/levels$ ./level01 aa
Fail.
프로그램을 실행해 인자로 아무값이나 전달해주면 Fail. 이라는 문자열이 뜨면서 종료된다.
디버깅해서 정답을 찾아야한다. 먼저 꼼수를 쓰자면 바이너리 파일에서 아스키 문자열을 확인할 수 있는 명령어가 있다.
프로그램을 실행해 인자로 아무값이나 전달해주면 Fail. 이라는 문자열이 뜨면서 종료된다.
디버깅해서 정답을 찾아야한다. 먼저 꼼수를 쓰자면 바이너리 파일에서 아스키 문자열을 확인할 수 있는 명령어가 있다.
level1@io:/levels$ strings level01
/lib/ld-linux.so.2
__gmon_start__
libc.so.6
printf
execl
puts
strncmp
_IO_stdin_used
__libc_start_main
GLIBC_2.0
PTRh
0Y_]
[^_]
[^_]
omgpassword
Usage: %s <password>
Win.
/bin/sh
Fail.
omgpassword 이라는 수상한 문자열이 있다. 한번 정답으로 넘겨줘보자.
omgpassword 이라는 수상한 문자열이 있다. 한번 정답으로 넘겨줘보자.
level1@io:/levels$ ./level01 omgpassword
Win.
sh-4.1$ id
uid=1001(level1) gid=1001(level1) euid=1002(level2) groups=1002(level2),1001(level1),1029(nosu)
정답을 찾았지만 우리는 겨우 strings 명령어 하나 배울려고 이 워게임을 복습하는것이 아니다.
바로 디버깅을 해보자
정답을 찾았지만 우리는 겨우 strings 명령어 하나 배울려고 이 워게임을 복습하는것이 아니다.
바로 디버깅을 해보자
level1@io:/levels$ gdb -q level01
Reading symbols from /levels/level01...done.
(gdb) disas main
Dump of assembler code for function main:
0x080483f4 <main+0>: lea 0x4(%esp),%ecx // ECX 에 (ESP+4) 주소값 복사 - ESP+4 -> argc
0x080483f8 <main+4>: and $0xfffffff0,%esp
0x080483fb <main+7>: pushl -0x4(%ecx)
0x080483fe <main+10>: push %ebp
0x080483ff <main+11>: mov %esp,%ebp
0x08048401 <main+13>: push %edi
0x08048402 <main+14>: push %ecx
0x08048403 <main+15>: sub $0x30,%esp // 프롤로그 부분 - 변수 48 바이트 선언, 스택 공간 생성
0x08048406 <main+18>: mov %ecx,-0x20(%ebp) // (EBP-32) 에 ECX 값 복사
0x08048409 <main+21>: movl $0x80485c8,-0xc(%ebp) // (EBP-12) 에 0x80485c8 값 복사
/* (gdb) x/s 0x80485c8
0x80485c8: "omgpassword"
정답이다, 이렇게 디버깅을 해서 바로 찾아낼 수 있다.
그러면 한번 어떻게 가지고노는지 디버깅을 계속 해보자
*/
/* (gdb) x/s 0x80485c8
0x80485c8: "omgpassword"
정답이다, 이렇게 디버깅을 해서 바로 찾아낼 수 있다.
그러면 한번 어떻게 가지고노는지 디버깅을 계속 해보자
*/
0x08048410 <main+28>: mov -0x20(%ebp),%eax // EAX 에 (EBP-32) 값 복사
0x08048413 <main+31>: cmpl $0x2,(%eax) // EAX 와 2 비교
/*
아마도 인자값을 비교하는것 같다. argv[0] argv[1] 일 경우에만 입력받는것 같다.
그걸 어떻게 알수있냐면 점프하지 않는곳, 즉 아래의 어셈블리어를 보면 "Usage: %s <password>\n"
라는 문자열을 출력하는데 이 문자열은 인자로, 정답으로 아무거나 전달하지 않았을경우나 한개 초과,
두개 이상 전달해줬을경우에만 나타난다. 즉, 인자를 비교하는것으로써 알수있다.
그러면 지금 (EBP-32) 와 EAX 에는 argc 가 들어가 있는 상태일것이다.
level1@io:/levels$ ./level01
0x08048413 <main+31>: cmpl $0x2,(%eax) // EAX 와 2 비교
/*
아마도 인자값을 비교하는것 같다. argv[0] argv[1] 일 경우에만 입력받는것 같다.
그걸 어떻게 알수있냐면 점프하지 않는곳, 즉 아래의 어셈블리어를 보면 "Usage: %s <password>\n"
라는 문자열을 출력하는데 이 문자열은 인자로, 정답으로 아무거나 전달하지 않았을경우나 한개 초과,
두개 이상 전달해줬을경우에만 나타난다. 즉, 인자를 비교하는것으로써 알수있다.
그러면 지금 (EBP-32) 와 EAX 에는 argc 가 들어가 있는 상태일것이다.
level1@io:/levels$ ./level01
Usage: ./level01 <password>
level1@io:/levels$ ./level01 a <---- cmpl $0x2,(%eax) 성립하는 조건, 참인 경우
Fail.
level1@io:/levels$ ./level01 a a
Usage: ./level01 <password>
*/
*/
0x08048416 <main+34>: je 0x8048439 <main+69> // 참일경우 (main+69) 로 점프 - 거짓일경우 계속 진행
0x08048418 <main+36>: mov -0x20(%ebp),%edx // EDX 에 (EBP-23) 값 복사
0x0804841b <main+39>: mov 0x4(%edx),%eax // EAX 에 (EDX+4) 값 복사
0x0804841e <main+42>: mov (%eax),%eax // EAX 에 EAX 값 복사
0x08048420 <main+44>: mov %eax,0x4(%esp) // (ESP+4) 에 EAX 값 복사
0x08048424 <main+48>: movl $0x80485d4,(%esp) // ESP 에 0x80485d4 값 복사
/*
*/
/*
(gdb) x/s 0x80485d4
0x80485d4: "Usage: %s <password>\n"*/
0x0804842b <main+55>: call 0x804832c <printf@plt> // printf 함수 호출, 위 문장 출력
0x08048430 <main+60>: movl $0x1,-0x1c(%ebp) // (EBP-28) 에 1 복사
0x08048437 <main+67>: jmp 0x80484b2 <main+190> // (main+190) 으로 점프
// 여기까지가 비교구문이 거짓일경우에 수행하는 문장이다.
// 여기까지가 비교구문이 거짓일경우에 수행하는 문장이다.
0x08048439 <main+69>: mov -0xc(%ebp),%eax // EAX 에 (EBP-12) 값 복사 - 현재 EBP-12 "omgpassword" = EAX
0x0804843c <main+72>: mov $0xffffffff,%ecx // ECX 에 -1 복사
0x0804843c <main+72>: mov $0xffffffff,%ecx // ECX 에 -1 복사
0x08048441 <main+77>: mov %eax,-0x24(%ebp) // (EBP-36) 에 EAX 복사 - 현재 EAX "omgpassword"
0x08048444 <main+80>: mov $0x0,%al // EAX 의 하위 ax의 하위 1바이트가 0 으로 복사된다. (0x80485c8 -> 0x8048500)
0x08048446 <main+82>: cld
0x08048447 <main+83>: mov -0x24(%ebp),%edi // EDI 에 (EBP-36) 값 복사 - 이제 EDI 에는 EAX 가 들어가있음
// EDI 에 정답이 들어가있는거나 마찬가지
// EDI 에 정답이 들어가있는거나 마찬가지
0x0804844a <main+86>: repnz scas %es:(%edi),%al
// 여기서 cld 와 repnz 의 중요한 설명이 필요하므로 따로 추가하겠다.
// 여기서 cld 와 repnz 의 중요한 설명이 필요하므로 따로 추가하겠다.
0x0804844c <main+88>: mov %ecx,%eax // EAX 에 ECX 값 복사 - (-13) 을 EAX 에 저장
0x0804844e <main+90>: not %eax // EAX 가 NOT 연산을 해서 -13 => 12 가 된다.
0x08048450 <main+92>: lea -0x1(%eax),%edx // EDX 에 (EAX-1) 주소값 복사
0x08048453 <main+95>: mov -0x20(%ebp),%ecx // ECX 에 (EBP-32) 값 복사 - argc 전달
0x08048456 <main+98>: mov 0x4(%ecx),%eax // EAX 에 (ECX+4) 값 복사
0x08048459 <main+101>: add $0x4,%eax // EAX + 4 - argc+4 => argv[1] 의 시작주소
0x0804845c <main+104>: mov (%eax),%ecx // ECX 에 EAX 값 복사
0x0804845e <main+106>: mov %edx,0x8(%esp) // (ESP+8) 에 EDX 값 복사 - argv[2]
0x08048462 <main+110>: mov -0xc(%ebp),%eax // EAX 에 (EBP-12) 값 복사
0x08048465 <main+113>: mov %eax,0x4(%esp) // (ESP+4) 에 EAX 값 복사 - argv[1]
0x08048469 <main+117>: mov %ecx,(%esp) // ESP 에 ECX 값 복사 - argv[0]
0x0804846c <main+120>: call 0x804830c <strncmp@plt> // 아하! strncmp 함수를 수행하기 위해 인자 세개를 받았군요,
/* int strncmp ( const char * str1, const char * str2, size_t num ); 이 인자들을 받아준거다.
120 에 브포를 걸고 edx, eax, ecx 하나하나 확인해보자
0x0804846c <main+120>: call 0x804830c <strncmp@plt> // 아하! strncmp 함수를 수행하기 위해 인자 세개를 받았군요,
/* int strncmp ( const char * str1, const char * str2, size_t num ); 이 인자들을 받아준거다.
120 에 브포를 걸고 edx, eax, ecx 하나하나 확인해보자
(gdb) x/s $edx
0xb: <Address 0xb out of bounds>
(gdb) x/s $eax
0x80485c8: "omgpassword"
(gdb) x/s $ecx
0xbfffdea4: "aaaa" <- 내가 입력한값과 omgpassword 를 비교한다
*/
0x08048471 <main+125>: test %eax,%eax // EAX 검사 - eflags 값이 바뀌는데 이 또한 자세하게 추가하겠다.
0x08048473 <main+127>: jne 0x804849f <main+171> // 0x804849f 로 점프 - 실패했을경우
0x08048475 <main+129>: movl $0x80485ea,(%esp) // ESP 에 0x80485ea 값 복사
/*
그러니깐 성공한 경우이다.
*/
/*
(gdb) x/s 0x80485ea
0x80485ea: "Win."그러니깐 성공한 경우이다.
*/
0x0804847c <main+136>: call 0x80482fc <puts@plt>
0x08048481 <main+141>: movl $0x0,0x8(%esp)
0x08048489 <main+149>: movl $0x80485ef,0x4(%esp)
0x08048491 <main+157>: movl $0x80485f2,(%esp)
0x08048491 <main+157>: movl $0x80485f2,(%esp)
0x08048498 <main+164>: call 0x80482ec <execl@plt>
// 쉘 띄우는 과정
// 쉘 띄우는 과정
0x0804849d <main+169>: jmp 0x80484ab <main+183>
0x0804849f <main+171>: movl $0x80485fa,(%esp) // ESP 에 0x80485fa 값 복사
0x0804849f <main+171>: movl $0x80485fa,(%esp) // ESP 에 0x80485fa 값 복사
0x080484a6 <main+178>: call 0x80482fc <puts@plt> //puts 함수호출
0x080484ab <main+183>: movl $0x0,-0x1c(%ebp) // (EBP-28) 에 0 복시
0x080484b2 <main+190>: mov -0x1c(%ebp),%eax // EAX 에 (EBP-28) 복사
0x080484b5 <main+193>: add $0x30,%esp // 스택 공간 초기화
0x080484b8 <main+196>: pop %ecx
0x080484b9 <main+197>: pop %edi
0x080484ba <main+198>: pop %ebp
0x080484bb <main+199>: lea -0x4(%ecx),%esp
0x080484be <main+202>: ret // 에필로그
End of assembler dump.
이로서 분석이 끝났다. 정답은 omgpassword 이다.
이로서 분석이 끝났다. 정답은 omgpassword 이다.
level1@io:/levels$ ./level01 omgpassword
Win.
sh-4.1$ id
uid=1001(level1) gid=1001(level1) euid=1002(level2) groups=1002(level2),1001(level1),1029(nosu)
sh-4.1$ cat /home/level2/.pass
WE5aVWRwYPhX
'스터디 > wargames' 카테고리의 다른 글
[USE-Wargames] IO SmashTheStack Level3 문제풀이 (0) | 2011.08.12 |
---|---|
[USE-Wargames] IO SmashTheStack Level2 문제풀이 (0) | 2011.08.12 |
SmashTheStack : level5@io.smashthestack 문제풀이 (0) | 2011.07.29 |
SmashTheStack : level4@io.smashthestack 문제풀이 (0) | 2011.07.29 |
SmashTheStack : level3@io.smashthestack 문제풀이 (0) | 2011.07.21 |