서버에 접속하여 passcode.c 파일을 보면 다음과 같다.

main 함수에서 welcome 함수와 login 함수를 실행하고 있고, wlecome 함수에서는 이름을 입력받아 출력하고 있고, login함수에서는 passcode1과 passcode2를 입력받고, 두 값이 모두 조건과 일치하면 시스템 함수로 cat flag를 실행한다. 그러나 두 값을 입력받는 곳을 보면 주소 연산자를 사용하고 있지 않아서 입력받아도 passcode1과 passcode2에는 입력받은 값이 들어갈 수 없다.

또한 login 함수에 있는 fflush(stdin)은 입력 버퍼를 지우는 코드이다. 그러나 리눅스에서 해당 코드는 실행이 안된다고 한다. 

welcome함수와 login함수를 gdb로 보면 다음과 같다. 

스택의 구조를 생각해보면 welcome 함수에서 name을 입력받기 전 0x70만큼의 공간을 확보하고 있고, login함수에서는 passcode를 입력받기 전 0x10만큼의 공간을 확보하고 있다. name의 크기는 100바이트 지만 0x70-0x10=0x60은 10진수로 96이므로 4바이트가 남고, int형 정수인 passcode1의 값을 변경시킬 수 있다. fflush의 got을 flag를 출력하는 시스템 함수의 주소로 바꾸면 flag를 출력할 수 있을 것 같다.

fflush plt에 들어가 fflush의 got주소를 구할 수 있다.

fflush의 got주소는 0x0804a004이다.  시스템 함수의 시작점은 0x080485e3이지만 scanf함수에서 정수로 받기 때문에 10진수로 변환하면 134514147 이다. 

따라서 다음과 같이 payload를 작성하면 플래그를 얻을 수 있다.

 

CTF에서 포너블 문제의 형식을 보면 바이너리가 주어지고, 문제 서버가 보통 nc서버로 주어진다. 바이너리를 분석하여 nc 서버에 payload를 보내서 문제를 해결하는 방식이다. 서버에 접속하면 바이너리가 바로 실행되는 형태가 많다. 이와 같은 상태의 서버를 구축하기 위해 xinetd를 설치해야 한다. xinetd는 네트워크에서 들어오는 요청을 받아 그 요청에 적절한 서비스를 실행한다. 요청은 포트번호를 식별자로 사용하여 구분한다.

$ sudo apt-get install xinetd

설치가 다 되었으면 /etc/xinetd.d 경로에 서비스 이름으로 설정 파일을 만들어야 한다. 테스트용 서비스로 hello를 만들것 이기 때문에 hello 파일을 만들었다. hello 파일에 다음과 같은 내용을 작성한다.

마지막 줄 server에 서버에 접속했을 때 실행시킬 바이너리 파일의 경로를 적어주면 된다.

이후 /etc/services 파일의 하단 # Local services 아래에 실행시킬 서비스와 포트 번호를 추가해준다.

이후 지정한 포트 번호로 nc 접속하면 서비스가 제대로 동작함을 확인할 수 있다.

테스트용 바이너리의 소스코드는 다음과 같다.

#include <stdio.h>

int main()
{
	printf("hello\n");
	return 0;
}

 

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C][pwnable.kr] random  (0) 2021.04.08
[Project H4C][pwnable.kr] passcode  (1) 2021.04.06
[Project H4C][pwnable.kr] flag  (0) 2021.04.02
[Project H4C][pwnable.kr] bof  (0) 2021.04.01
[Project H4C][pwnable.kr] collision  (0) 2021.03.30

문제 파일을 file 명령어로 확인해보면 리눅스 64비트 실행파일임을 확인할 수 있다.

gdb로 파일을 열어보면 함수 목록도 확인할 수 없었고, main 함수도 확인할 수 없었다.

문제 설명을 보니 pack 라는 단어가 있었고, 리버싱 문제라고 한다. 그래서 exeinfo라는 툴을 통해 패킹 된 파일인지 확인해 보았다.

upx라는 패커로 패킹된 것을 확인할 수 있었고, exeinfo에서 제공해주는 github 사이트에서 언팩 툴을 구할 수 있었다.

upx.exe -d 옵션으로 언패킹 할 수 있었다.

언팩 된 flag 파일을 아이다로 열어보면 main 함수를 확인할 수 있었고 main 함수에서 flag를 들어가 보면 플래그로 보이는 문자열을 찾을 수 있었다.

 

문제에 접속하여 파일 목록을 보면 col과 flag, col.c 파일이 있고, flag 파일은 col 계정으로 읽을 권한이 없으며 col에 setuid가 걸려있기 때문에 col을 통해 flag파일을 읽을 수 있을 것 같다. col의 소스 파일은 다음과 같다.

hashcode 변수에 0x21DD09EC로 설정되어 있다.

check_password 함수를 보면 인자를 정수로 형변환하고 있고, 4번 반복하여 res에 하나씩 더한다. 정수형 변수이기 때문에 4바이트 이다. res = ip[0] + ip[1] + ip[2] + ip[3] + ip[4]로 총 20바이트가 된다.

프로그램을 실행할 때 인자가 없으면 usage로 시작하는 문자열이 출력되면서 종료되고, 인자 크기가 20이 아니면 passcode 가 꼭 20바이트가 되야 한다는 내용의 문자열이 출력되며 프로그램이 종료된다. 

hashcode의 값(0x21DD09EC)과 check_password 함수에 인자를 넣은 값이 같다면 시스템 함수로 flag 파일을 읽는다.

0x21DD09EC를 5로 나누면 0x6C5CEC8가 나오므로  0x6C5CEC8 * 4 + 0x6C5CECC 는 0x21DD09EC가 된다. col을 실행시키면서 저 값을 리틀 엔디언으로 넣으면 다음과 같이 플래그를 얻을 수 있다.

 

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C][pwnable.kr] flag  (0) 2021.04.02
[Project H4C][pwnable.kr] bof  (0) 2021.04.01
[Project H4C][pwnable.kr] fd  (0) 2021.03.30
[Project H4C] FTZ 12  (0) 2021.03.29
[Project H4C] FTZ (8 ~11)  (0) 2021.03.27

문제 서버에 접속하면 다음과 같이 flag 파일이 있고, set uid가 걸려있는 파일이 있다.

flag 파일은 fd 계정으로는 읽을 권한이 없어서 setuid가 걸린 fd를 통해 flag파일을 확인할 수 있을 것 같다. fd의 소스코드로 보이는 fd.c의 내용은 다음과 같다.

fd를 실행할 때 인자가 없으면 pass로 시작하는 문자열을 출력하고 프로그램을 종료한다.

fd를 argv[1] - 0x1234로 초기화하고 len에 read함수로 buf에서 32바이트를 읽어오고 있다. read함수의 첫번째 인자는 fd(파일 디스크립터)라고 한다. 파일 디스크립터는 0은 표준 입력, 1은 표준 출력, 2는 표준 에러 이다. 따라서 위 소스에서 fd가 0이 되면 입력 받을 수 있고, 입력받은 내용이 buf에 들어간다. 그리고 buf가 LETMEWIN이라면 시스템 함수로 flag를 출력한다.

fd가 0이되려면 0x1234는 4660이므로 인자로 4660을 넣으면 fd가 0이되서 표준 입력으로 read함수를 실행하기 때문에 LETMEWIN을 입력하면 조건문을 만족시켜 플래그가 출력된다.

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C][pwnable.kr] bof  (0) 2021.04.01
[Project H4C][pwnable.kr] collision  (0) 2021.03.30
[Project H4C] FTZ 12  (0) 2021.03.29
[Project H4C] FTZ (8 ~11)  (0) 2021.03.27
[Project H4C] FTZ (1 ~ 7(문제오류))  (0) 2021.03.24

hint 파일의 내용은 다음과 같다.

setuid 함수로 level 13 계정의 uid로 바꿔주고 있고, gets 함수로 입력을 받는다. 입력을 받는 str의 크기는 256바이트 이지만, 입력값에서 제한을 하고 있지 않기 때문에 bof 취약점이 발생할 수 있다. 정상적인 입력값을 받는다면 문자열을 입력받고, 입력값을 그대로 출력해주는 프로그램이다. 

파일 목록을 보면 attackme라는 파일이 있었고, 그 파일을 tmp 디렉토리로 복사하여(권한문제 때문) gdb로 main 함수를 확인하며 다음과 같다.

str의 크기는 256이지만 264 만큼의 크기를 확보하고 있기에 str 256바이트에 dummy 8바이트가 들어가는 것 같다. str의 시작점에서 ret까지의 거리는 str의 크기 256 + dummy(8) + SFP(4) = 268이다. 전 문제 처럼 환경변수에 쉘 코드를 넣고, RET에 환경변수의 주소를 넣어 level 13 계정의 쉘을 딸 수 있을 것 같다.

사용한 쉘 코드는 전 문제와 동일하다.

\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80

SHELL12 라는 이름으로 환경변수를 만들어 쉘 코드를 넣어주었다.

다음과 같은 코드로 쉘 코드를 넣은 환경변수의 주소를 알아낼 수 있다.

페이로드를 넣을 때는 전 문제와 달리 프로그램 실행 후 값을 입력받는 방식이기 때문에 "넣을 값"; cat | ./attackme의 형식으로 실행하면 넣을 값이 attackme 실행후 값으로 들어가고, 값을 입력할 수 있게 된다.

따라서  다음과 같이 payload를 작성하면 쉘을 딸 수 있다.

$ (python -c 'print "A"*268+"\x18\xfe\xff\xbf"'; cat) | ./attackme

 

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C][pwnable.kr] collision  (0) 2021.03.30
[Project H4C][pwnable.kr] fd  (0) 2021.03.30
[Project H4C] FTZ (8 ~11)  (0) 2021.03.27
[Project H4C] FTZ (1 ~ 7(문제오류))  (0) 2021.03.24
[Project H4C] C언어 코딩도장(14)  (0) 2021.03.23

Level 8

문제의 힌트는 다음과 같다.

find 명령어의 size 옵션을 활용해서 2700 용량을 가진 파일을 찾을 수 있었다. 크기 뒤에 b, c, k, w를 붙여 확인해본 결과 2700은 바이트 단위임을 알 수 있었다.

찾은 found.txt 파일을 열어보니 다음과 같이 level9의 shadow 파일임을 알 수 있었다.

파일의 내용을 존 더 리퍼라는 패스워드 크랙 툴을 이용하여 크랙하면 다음과 같은 비밀번호를 얻을 수 있다.

 

Level 9

문제의 hint파일의 내용은 다음과 같다.

bof파일을 통해 level10의 권한을 얻어야 하는것 같고, buf2의 앞 두글자가 go와 같으면 시스템 함수를 실행시켜 주는 것 같다. 입력값은 buf로 받고 있는데, buf의 크기는 10인데, 입력값 제한을 40으로 하고 있어서 bof가 발생한다.

gdb로 main함수를 보면 다음과 같다.

입력값은 ebp - 40에 들어가고 있고, strncmp로 비교하는 값은 ebp-24 에 들어가고 있다. ebp - 40이 buf이고, ebp-24가 buf2인 것이다. 메모리 공간이 16만큼 차이가 나므로 프로그램을 실행하고 입력할 때 16개만큼 다른 값으로 채우고, go를 넣으면 buf2에 go가 들어가서 조건문을 만족시킬 수 있다.

 

Level 10

시스템에서 프로세스의 메모리는 그 프로세스만 접근이 가능하지만, 공유 메모리를 사용하게 되면 다른 프로세스에서도 메모리에 접근할 수 있다.  공유메모리의 key_t값이 주어졌기 때문에 이 키 값의 공유메모리를 사용하는 프로그램을 만들어서 대화 내용이 있는 메모리에 접근할 수 있을 것 같다.

다음과 같이 C코드를 작성하여 위 힌트의 대화방과 같은 키값을 사용하여 메모리를 공유하는 프로그램을 만들어 줬다.

공유메모리를 생성하려면 sys/shm.h 헤더파일과 sys/ipc.h헤더파일을 사용해야 한다. shmget 함수로 7530 키를 가진 공유 메모리를 생성할 수 있고 shmat 함수로 공유메모리 프로세스에 접근할 수 있다. 메모리 주소를 반환하며 SHM_RDONLY옵션을 사용하면 읽기 전용이다. 메모리에 저장된 값을 출력하면 다음과 같은 내용이 나와 level11의 비밀번호를 알 수 있다.

 

Level 11

hint파일의 내용은 다음과 같다.

파일 목록을 보면 attackme 라는 파일이 있는 것을 확인할 수 있다.

힌트 파일의 내용이 attackme 파일의 소스코드 인 것 같다. 인자로 문자열을 받고 있고 인자로 받은 문자열을 str에 저장하고, str을 출력하는 프로그램이다. 

문제 파일을 gdb로 실행하면 권한에 의한 오류가 발생하기 때문에 파일을 복사하여 복사한 파일을 분석해야 한다.

gdb로 main 함수를 보면 다음과 같다.

ebp - 264를 사용하는 것으로 보아 256크기의 str 변수에 8바이트의 dummy가 들어가는 것 같다. 쉘 코드를 str에 넣고, str에서 bof를 발생시켜 ret까지 덮은 후에 ret에 str의 주소를 넣어 쉘 코드를 실행시킬 수 있을것 같아서 시도해보니 str의 주소가 프로그램을 시작할때마다 무작위로 바뀌는 aslr 보호 기법이 적용되어 있어서 불가능할 것 같다.

다른 방법을 찾아보다 환경변수는 리눅스 시스템에 저장되어 있기 때문에 한번 설정하면 주소가 바뀌지 않아서 환경 변수에 쉘 코드를 넣고 ret에 환경변수의 주소를 덮으면 쉘을 딸 수 있다고 한다.

사용한 쉘 코드는 다음과 같다.

\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80

다음과 같이 export 명령으로 환경변수에 쉘 코드를 넣을 수 있다. 환경변수 이름은 SHC로 하였다. 또한 env 명령으로 설정한 환경변수를 확인할 수 있다.

환경변수의 주소는 stdlib.h 헤더의 getenv()함수로 알아낼 수 있다. 다음과 같이 c코드를 짜고 컴파일하여 실행하면 설정한 환경변수의 주소를 알아낼 수 있다.

이제 str크기(256) + dummy(8) + SFP(4) = 268만큼 덮고 ret에 저 주소를 리틀엔디언 방식으로 덮으면 쉘을 딸 수 있다.

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C][pwnable.kr] fd  (0) 2021.03.30
[Project H4C] FTZ 12  (0) 2021.03.29
[Project H4C] FTZ (1 ~ 7(문제오류))  (0) 2021.03.24
[Project H4C] C언어 코딩도장(14)  (0) 2021.03.23
[Project H4C] C언어 코딩도장(13)  (0) 2021.03.23

Level 1

level 1에 접속하여 파일 목록을 확인하면 hint파일이 있는 것을 확인할 수 있다.

hint 파일을 읽어보면 "level2 권한의 setuid가 걸린 파일을 찾는다." 라고 쓰여 있다.

파일을 찾는것은 find 명령어를 통해 찾을 수 있으며 -user 옵션을 통해 파일 소유자를, -perm 옵션은 권한을 의미하며 4000 권한은 setuid가 설정되어 있음을 의미한다. 따라서 다음과 같은 명령어로 힌트로 주어진 파일을 찾을 수 있다.

$ find / -user level2 -perm -4000 2>/dev/null

2>/dev/null은 표준에러(2)가 발생하면 /dev/null(리눅스의 휴지통)으로 넣어준다는 의미이다.

명령어를 실행하면 다음과 같은 결과가 나온다.

/bin/ExecuteMe 파일을 실행하면 level2 권한으로 명령어를 실행시켜준다고 나오고, /bin/bash 명령을 입력하면 level2의 쉘을 딸 수 있다.

 

Level 2

hint 파일을 읽어보면 텍스트 파일 편집 중 쉘의 명령을 실행시킬 수 있다고 한다.

level3 권한으로 setuid가 걸려있는 파일을 확인해보면 다음과 같다.

editor을 실행시키면 vim 텍스트 에디터가 실행된다.

vim 텍스트 에디터에서는 ! 뒤에 명령어를 사용하면 쉘 명령어를 사용할 수 있다.

! id로 level3 사용자 권한으로 명령어를 실행한다는 것을 알 수 있다.

! my-pass로 level3의 비밀번호를 확인할 수 있고 ! /bin/bash로 쉘을 딸 수 있다.

 

Level 3

hint 파일을 읽어보면 다음과 같다.

C 코드를 읽어보면 인자의 갯수가 2가 아니면 if문이 실행되면서 printf함수로 출력하고 프로그램을 종료한다. cmd라는 배열에 dig @와 argv[1] 인자로 준 값, 이후 문자열이 들어가고 있고 시스템 함수로 cmd 배열의 문자열을 실행한다. autodig 프로그램을 실행하면서 인자로 명령어를 넣어줘야 하는데 이미 앞에서 dig 명령어가 사용되고 있기 때문에 동시에 여러 명령어를 사용하려면 세미클론을 사용하여 인자를 전달하면 된다.

autodig 프로그램은 find명령어로 찾으면 다음과 같은 곳에 있다.

autodig를 실행하고 인자로 ";/bin/bash;"를 넣어주면 level4의 쉘을 딸 수 있고, my-pass 명령어로 비밀번호를 확인할 수 있다.

 

Level 4

hint 파일을 보면 "누군가 /etc/xinetd.d/에 백도어를 심어놓았다.!" 라고 한다.

해당 경로의 파일 목록을 보면 다음과 같이 backdoor파일을 확인할 수 있다.

backdoor파일의 내용을 보면 다음과 같다.

finger 이라는 서비스를 통해 level5의 권한으로 /home/level4/tmp/backdoor이라는 서버 파일을 실행한다. 

finger 명령어는 리눅스에서 사용자의 계정정보를 확인하는 명령어이다. finger을 실행하면 backdoor 파일의 내용으로 인해 /home/level4/tmp/backdoor 파일이 실행될 것 같다.

tmp 폴더로 이동하여 backdoor 파일을 만들어야 한다.

시스템함수로 my-pass 명령을 실행하는 c 코드를 작성하고 gcc로 컴파일 하고 finger명령어를 실행하면 비밀번호를 알 수 있다.

 

Level 5

hint 파일을 읽어보면 다음과 같다.

힌트의 level5 파일은 level6 계정 권한으로 setuid가 걸려있음을 확인할 수 있다.

level5를 실행하고 /tmp 디렉토리를 확인해보면 level5.tmp라는 임시파일이 없다. 임시파일을 만들고 삭제시켜주는것 같다.

생성되는 임시파일을 이용하여 권한상승을 하는 레이스 컨디션 공격 기법이 있다고 한다.

레이스 컨디션(Race Condition)은 한정된 자원을 동시에 이용하려는 여러 프로세스가 자원의 이용을 위해 경쟁을 벌이는 현상이라고 한다. 레이스 컨디션을 이용한 공격은 취약 프로그램이 생성하는 임시 파일의 이름을 파악하고, 그 임시파일과 같은 이름의 파일을 생성히고 이 파일에 심볼릭 링크를 생성한 후 원본 파일을 지운다. 원본 파일이 지워진 상태에서 취약한 프로그램이 심볼릭 링크를 건 파일과 같은 파일을 생성할 때를 기다렸다가 심볼릭 링크를 이용해 파일의 내용을 변경한다. 

이 문제의 경우 취약한 파일은 level5 이고, 임시파일의 이름은 level5.tmp가 된다.

tmp 디렉토리에 level5.tmp에 심볼릭 링크로 연결할 파일을 하나 만들고 심볼릭 링크로 연결했다.

이후 level5를 실행하면 심볼릭링크로 연결된 level5에 level5.tmp의 내용이 저장되고 /tmp/level5파일의 내용을 확인하면 다음 레벨의 비밀번호를 확인할 수 있다.

 

Level 6

level6 계정으로 접속하면 다음과 같은 힌트가 나오고, 텔넷 접속 서비스가 나온다.

번호를 입력하면 ssh 연결이 끊기고, ctrl + c로 현재 프로그램을 종료하려고 하면 ctrl + c를 사용할 수 없다고 한다. 

다시 level6 계정으로 접속해서  힌트만 보이는 화면에서 ctrl + c를 누르면 현재 프로그램이 강제 종료되고 프롬프트가 나온다. 파일 목록을 확인해보면 password 파일이 있고 password파일을 확인해보면 level7계정의 비밀번호를 알아낼 수 있다.

 

Level 7

hint 파일을 보면 다음과 같은 내용이 나온다.

level7 을 실행해보면 wrong.txt가 존재하지 않는다는 메시지가 나오면서 문제를 더이상 진행할 수 없다.

 

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C] FTZ 12  (0) 2021.03.29
[Project H4C] FTZ (8 ~11)  (0) 2021.03.27
[Project H4C] C언어 코딩도장(14)  (0) 2021.03.23
[Project H4C] C언어 코딩도장(13)  (0) 2021.03.23
[Project H4C] PLT, GOT  (0) 2021.03.21

버퍼는 지정된 크기의 메모리 공간이라는 뜻이다.

버퍼 오버플로우는 버퍼가 지정한 크기의 데이터 보다 더 많은 값이 저장되서 버퍼가 넘치는 취약점이다.

발생하는 위치에 따라 스택 버퍼 오버플로우, 힙 오버플로우 같이 구분된다.

1
2
3
4
5
6
7
8
9
#include <stdio.h>
#include <stdlib.h>
 
int main(void) {
    char buf[16];
    gets(buf);
    
    printf("%s", buf);
}
cs

위 코드는 16바이트 버퍼를 스택에 할당하고 있고, gets함수를 통해 입력값을 할당한 스택에 저장하고 있다. 이때 gets 함수에서 입력값에 대해 제한을 하고 있지 않기 때문에 16바이트 이상의 값이 들어가게 되면 스택 버퍼 오버플로우가 발생하게 된다.

할당된 크기 이상의 입력값으로 버퍼를 오버플로우 시켜 프로그램의 ret에 쉘 코드를 덮어쓰거나(NX 보호기법이 적용되지 않은 경우), 다른 함수의 주소를 덮어써서 리턴하면서 버퍼 오버플로우 취약점을 이용할 수 있다.

 

'Project H4C Study Group' 카테고리의 다른 글

[Project H4C] PLT, GOT  (0) 2021.03.21
[Project H4C] SFP, RET  (0) 2021.03.21
[Project H4C] pwntools  (0) 2021.03.20
[Project H4C][dreamhack] basic_exploitation_002  (0) 2021.03.19
[Project H4C][dreamhack] basic_exploitation_001  (0) 2021.03.19

+ Recent posts