2021. 2. 2. 12:13ㆍFTZ
[ Level 9 ]
level9 로그인
ID : level9
PW : apple
힌트에 나온 /usr/bin/bof를 실행하면,
"It can be overflow : " 가 출력된다.
힌트에 나온 소스코드를 보고, Overflow를 시켜 해결해야 하는 것 같다.
우선 위의 소스코드를 분석해보면,
buf 배열과 buf2 배열은 각각 char형으로 10씩 만들어졌다.
따라서 메모리에는 buf와 buf2가 10byte씩 공간을 차지하고 있다는 말이다.
fgets함수를 통해 buf에 길이 40까지의 문자를 입력할 수 있다.
하지만 if문을 보면 buf에 입력을 하였으나, strncmp를 통해 비교하는 것은 buf2이다.
if문의 내용은 buf2의 인덱스 2까지의 문자열이 "go"와 같은지 비교한다는 내용이다.
fgets에서 길이 40까지 입력이 가능하기 때문에
buf의 배열 공간인 10을 넘겨서 buf2까지 입력을 할 수 있을 것이라 생각하였다.
그래서 앞에 10개의 문자는 의미 없는 문자를 입력하고 마지막에 go를 적어보았다.
하지만 성공하지 못하였다.
그래서 gdb를 사용하여 assembly 코드를 보며 buf와 buf2 사이의 길이가 얼마나 되는지 알아볼 것이다.
※ gdb란? GNU 디버거(GNU Debugger)라고 하며, 보통은 GDB라고 부른다. gdb는 GNU 소프트웨어 시스템을 위한 기본 디버거이다. gdb 디버깅을 시작하는 방법은 두 가지가 있다. gdb 실행 시 디버깅할 파일을 입력하는 방법과 gdb내에 들어가서 file 명령을 사용하여 파일을 입력하는 방법이 있다. $ gdb a.out ( 또는 ) (gdb) file a.out gdb를 종료하고 싶다면 quit를 입력하면 된다. |
gdb를 실행하면 /usr/bin/bof : Permission denied라고 출력된다.
즉, 권한이 없다는 뜻이다.
그 이유는
level9은 실행할 수 있는 권한만 있기 때문이다.
하지만 우리에게는 힌트에서 주워진 /usr/bin/bof의 소스코드가 있다.
힌트에 있는 소스코드를 복사하여 tmp 디렉터리로 이동한 후,
vi를 이용하여 소스코드를 붙여 넣기 하여, c파일을 만들어 준다.
다음으로 gcc명령어를 통하여 실행파일을 만들어 준다.
이후 bof 파일을 gdb로 실행하면 된다.
gdb를 통해 bof를 disassemble 할 것이다.
이는 C 언어로 구현된 코드를 Assembly 코드로 보여주는 것이다.
set disassembly-flavor 명령어로 Assembly의 문법을 선택할 수 있다.
( ※ Assembly에는 AT&T와 Intel 문법이 존재한다. )
set disassembly-flavor intel을 입력하여, intel문법으로 선택해준 뒤,
( 개인적으로 Intel 문법이 보기 쉽다. )
disass main 혹은 disaassemble main을 입력하여 main함수를 disassemble 해준다.
disassemble 하게 되면 Assembly 코드가 출력이 된다.
가장 왼쪽은 메모리 상의 주소이며, <main+n>은 main의 시작부터 메모리 주소가 n만큼 차이 난다는 것을 의미한다.
그 외에는 모두 Assembly 코드라고 볼 수 있다.
※ Assembly 문법 Operand는 Destination과 Source 2가지가 존재한다. |
위의 Assembly 코드를 보면 call이라는 명령어가 있다.
call은 함수를 호출한다는 의미인데, 어셈블리에서 함수를 호출할 때,
매개변수를 보내는 방법은 함수로 보낼 매개변수들을 뒤에서부터 push 시킨 후,
call을 통해 함수를 호출합니다.
C 코드에서 fgets함수에는 (buf, 40, stdin)을 매개변수로 보냈고,
strncmp함수에는 (buf2, "go", 2)을 매개변수로 보냈습니다.
그렇다면 fgets의 매개변수는 각각 ds:0x8049698, 0x28, eax이며,
ds:0x8049698은 stdin을 0x28은 40을 [ebp-40]의 주소를 저장한 eax는 buf를 의미하게 됩니다.
이를 확인할 수 있는 방법은 gdb에서 x 명령어를 실행하면 됩니다.
※ gdb x 명령어 x 명령어를 사용하여 해당 메모리를 조사할 수 있다. <Option> t : 2진법으로 보여준다. 0 : 8진법으로 보여준다. u : 10진법으로 보여준다. x : 16진법으로 보여준다. b : 1 byte 단위로 보여준다. h : 2 byte 단위로 보여준다. w: 4 byte 단위로 보여준다. g : 8 byte 단위로 보여준다. i : 역어셈블된 명령어의 명령 메모리를 볼수 있다. c : ASCII 표의 바이트를 자동으로 볼 수 있다. s : 문자 데이터의 전체 문자열을 보여준다. < 사용법 > (gdb) x/[Option] [메모리] |
위처럼 0x8049698의 메모리 영역에는 stdin이 저장되어 있는 것을 알 수 있다.
또한 0x28을 10진수로 나타내면 40이다.
따라서 [ebp-40]은 buf의 주소라는 것을 알 수 있으며,
strncmp에서도 매개변수는 각각 0x2, 0x804856a이며,
0x2를 10진수로 나타내면 2이고, 0x804856a는 "go" 이므로,
[ebp-24]는 buf2의 주소라는 것을 알 수 있습니다.
※ Assembly에서 lea 명령어는 주소를 복사하는 명령어이다.
따라서 buf의 주소 [ebp-40]과 buf2의 주소 [ebp-24]는 16만큼의 차이가 있다는 것을 알아내었습니다.
이제 tmp에 있는 bof로 테스트를 해봅시다.
총 16개의 a를 입력하고 그 뒤에 go를 입력하자 Good Skill! 이 출력되면서 if문을 통과했다는 것을 알 수 있습니다.
통과했다는 것을 알았으니, /usr/bin/bof를 실행하여 봅시다.
실행한 후 똑같이 입력해보니 사용자가 level10으로 바뀌었습니다.
이는 소스코드에 있는 setreuid를 통해 uid를 3010( level10 )으로 바뀌었기 때문입니다.
※ setuid비트를 실행파일에 적용하면 실 사용자(프로그램을 사용하는 사용자)에서
프로그램의 소유자의 ID로 유효 사용자(EUID)가 바뀌게 된다.
이를 알아보는 방법은 id 명령어를 이용하면 쉽게 알 수 있다.
※ id 명령어 id 명령어를 사용하면 uid를 알 수 있다. <사용법> id [Option] [사용자명] <Option> -g ( --group ) : 사용자의 그룹 id만 출력 -G ( --groups ) : 추가 그룹의 id만 출력 -u ( --user ) : 사용자의 UID를 출력 -n ( --name ) : -u, -g, -G 옵션과 함께 사용하며 해당하는 id의 이름만 출력 -r ( --real ) : -u, -g, -G 옵션과 함께 사용하며 해당하는 실제 id를 출력 |
위처럼 uid가 3010( level10 )으로 바뀐 것을 확인할 수 있다.
my-pass를 입력하면 level10의 비밀번호를 알 수 있다.
[ Level 9 Clear ]
'FTZ' 카테고리의 다른 글
[FTZ] Level 11 (0) | 2021.02.15 |
---|---|
[FTZ] Level 10 (0) | 2021.02.02 |
[FTZ] Level 8 (0) | 2021.01.12 |
[FTZ] Level 7 (0) | 2021.01.05 |
[FTZ] Level 6 (0) | 2021.01.05 |