혜랑's STORY

[LOB RedHat] Lv 2. gremlin -> cobolt 본문

2021 SISS 21기 활동/겨울방학 System

[LOB RedHat] Lv 2. gremlin -> cobolt

hyerang0125 2021. 1. 30. 00:44

문제를 풀기 위해 xshell에서 로그인 해 주었다.

Id : grmlin / Pw : hello bof world

가장 먼저 존재하는 파일을 알아보기 위해 ls-l 명령어를 실행하였다. 

그 결과 cobolt.c 파일과 cobolt라는 파일이 있는 것을 확인할 수 있다. cobolt 파일은 colbolt.c 파일을 컴파일하여 만들어진 파일인 것 같다. cobolt.c 파일을 열어 내용을 확인해 보았다.

Lv.1 문제와 같이 strcpy 함수를 사용하여 문자열의 길이를 검사하지 않는다는 취약점이 있었다. 그러나 이번 문제에서는 buffer에 16바이트를 할당하였기 때문에 버퍼에 공격 코드를 담기엔 충분하지 못하다.

일단 권한 문제를 해결하기 위해 cp 명령어를 통해 복사를 해주었고, 그 결과 gremlin에게 권한이 있는 바이너리가 생성되게 되었다.

이제 gdb를 사용하여 main 함수의 어셈블리 코드를 살펴보자.

  • set disassembly-flavor intel : 어셈블리 코드 문법을 intel로 설정
  • disas [함수이름] : 함수의 어셈블리 코드를 보는 명령어

main 함수의 어셈블리 코드

gdb를 통하여 스택의 크기가 정말 16이라는 것을 확인하였고, 스택 상황은 아래와 같다고 생각해 볼 수 있다.

buffer SFP RET(return)
16 4 4

역시 buffer는 쉘코드를 담기엔 크기가 너무 작은 것 같다. 따라서 다른 메모리에 쉘코드를 저장하기로 하였다. 스택 영역에는 지역변수, 환경변수, 실행인자(argv) 등이 존재하고 있으며 이 모든 공간은 쉘코드를 저장 할 수 있다. 난 이번 문제를 해결하기 위해 실행인자에 쉘코드를 널어보기로 하였다.

argv[1]은 버퍼로 복사가 되므로 16바이트 밖에 사용하지 못한다. 따라서 argv[1]에 RET가 argv[2]를 가르기토록 하여 공격할 것이다.

가장 먼저 argv[2]의 주소를 찾아야 한다. 따라서 bp는 strcpy함수가 끝난 후의 지점에 설정하고, 실행 인자로 "A"*24와 "B"*100을 따로 넘겨주었다.

b * main+74
`python -c 'print "A"*24'` `python -c 'print "B"*100'`

인자를 넘겨줄 때, argv[1]에는 "A"를, argv[2]에는 "B"를 넘겨주었기 때문에 x/1000x $esp 명령어를 사용하여 메모리에 쌓여있는 것을 확인할 때, 0x41414141에서 0x42424242으로 바뀌는 지점이 바로 argv[2] 주소의 시작이다.

 

역시 4141에서 4242로 바뀌는 부분이 있다. 이제 "B"가 들어있는 주소 중 아무곳이나 하나 골라 쉘코드를 넣어주면 된다! 나는 0xbffffc3c로 정하였다.

사용할 코드의 구조는 다음과 같다.

기존 buffefr + SFP (20 byte) argv[2]의 주소 : 0xbffffc3c shellcode

이대로 공격 코드를 작성해 보았다.

./cobolt `python -c 'print "A"*20 + "\x1c\xfc\xff\xbf" '`  `python -c 'print "\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"'`

코드를 실행시킨 결과 역시 쉘이 실행되었다.

이렇게 gremlin에서 cobolt로 가는 비밀번호를 알아내었다.