본문 바로가기

5. 방학 활동/Write UP

[2023.07.24] 워게임 문제풀이(1) - 1

문제1 - Return address overwrite

문제 파일인 rao.c 파일을 컴파일해 실행해준다.

그리고 64개 이상의 문자열을 입력해보면 이렇게 segmentation fault라는 에러가 나게 된다.

입력을 받는 buf 버퍼의 크기가 0x28로, 이 이상 입력시 에러가 발생한다.

따라서 이 점을 이용해 버퍼 오버플로우 공격을 시도할 것이다.

 

gdb로 컴파일한 rao 파일을 열어 disass main 명령어로 main함수의 어셈블리를 확인한다.

main+35에 이렇게 [rbp-0x30]에 버퍼가 위치하는 것을 알 수 있다.

또한 스택이 버퍼 30 크기 + SFP 8크기 + return address 8 크기로 구성됐을 것이라 추측해볼 수 있다.

get_shell의 주소를 알아내어 buf크기(0x30) + sfp크기(0x08) + get_shell 주소를 넣을 것이다.

get_shell의 주소는 0x4006aa으로 리틀 엔디언으로 \xdd\x11\x40\x00\x00\x00\x00\x00,

따라서 페이로드는 b'A'*0x30 + b'B'*0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00'가 된다.

페이로드를 덮어씌우는 코드를 작성해 실행하면 flag값을 획득할 수 있다.


문제2 - fd

파일 디스크립터를 알아내는 문제다. 파일 디스크립터는 프로세스가 파일에 접근할 때 사용되는 인덱스이다.

putty를 사용해서 열고 로그인을 한다.

아무 정보도 없기 때문에 어떤 파일이 존재하는지 알기 위해서 ls-l을 사용한다.

fd, fd.c, flag라는파일이 존재하는 것을 알 수 있다. fd.c 파일을 읽기 위해 cat을 사용할 것이다.

*인자를 넣는 방법: ./파일이름 인자값

*atoi 함수: char형 데이터를 int형 데이터로 변환하는 함수

*read 함수: read(파일디스크럽터, 저장할 버퍼 포인터, 저장할 버퍼길이)

*strcmp 함수: 문자열을 비교하는 함수, 같으면 0, 다르면 1를 반환함

 

첫번째 if문의 코드가 인자가 없을 경우 pass argv[1] a number\n 를 출력하라는 의미로, 인자를 하나 이상 넣어 다음 코드가 실행되게 해야한다.

atoi 함수를 통해 우리가 넣은 인자값에 0x1234를 빼고 fd에 저장하는 것을 알 수 있다.

read함수에 파일디스크럽터의 값이 0이 되게 만들어서 키보드로 입력 받은 값을 읽어 저장하게 한다.

strcmp 함수 앞에 !이 붙어서 같으면 1이 나올 것이므로 LETMEWIN/n과 buf를 같게 만들어 if문을 참으로 만들어야 한다. 따라서 fd값이 0이 되어야한다. 0x1234는 10진수 4660로 인자값으로 4660을 넣어주면 입력을 기다리고 있음을 알 수 있다.

 

 LETMEWIN을 입력하면 플래그가 나오는 것을 볼 수 있다.


문제3 - collision

문제에서 MD5 hash collision을 원한다.

해시 충돌이란 해시 함수가 서로 다른 두 개의 입력값에 대해 동일한 출력값을 내는 상황을 의미한다.

MD5(Message-Digest algorithm 5)은 임의의 길이의 값을 입력 받아서 128비트 길이의 해시값을 출력하는 알고리즘이다. MD5는 단방향 암호화이기 때문에 출력 값에서 입력값을 복원하는 것은 일반적으로 불가능하다. 같은 입력값이면 항상 같은 출력값이 나오고, 서로 다른 입력값에서 같은 출력값이 나올 확률은 극히 낮다. 

putty를 통해 열어서 디렉토리 내 파일 목록을 확인한다.

cat을 통해 col.c 파일을 읽으니 다음과 같은 코드를 확인할 수 있었다.

main 함수부터 보면 첫번째 if문에서 인자값 argc의 개수가 2개 이상이어야 한다.

두번째 if문에서는 인자값 argv[1]의 길이가 20바이트여야한다는 것을 알 수 있다.

세번째 if문에서는 해시코드와 check_password 함수 결과값이 같을 경우 플래그를 얻을 수 있다.

check_password 함수를 확인해보면 const char* p로 문자열을 인자로 받아 p의 주소값을 int형 포인터 변수 ip에 넣는다. 그 후 int형 변수 res에 ip[0]~ip[4] 값의 총합을 넣는다. 이때 ip는 int형이기 때문에 4바이트 단위로 5개의 문자열을 더하는 것이다.

따라서 해시코드와 check_password 함수값이 같으려면 5개의 문자열의 합이 해시코드와 같아야 한다.

21DD09EC는 10진수로 568134124 이다. 5의 배수가 아니기 때문에 4개의 같은 문자와 마지막 문자에 나머지가 합해진다는 것을 알 수 있다.

 

6c5cec8 4개와 6c5cecc의 합을 입력하면 플래그를 얻을 수 있다.


문제4 - welcome

문제 정보를 읽어보면 ‘접속 정보 보기’를 눌러 서비스 정보를 가지고 서버에 접속하여 플래 그를 획득하는 것임으로 알 수 있다.

 

접속 정보 보기를 눌러 확인해 보니 서버 주소를 확인할 수 있고 해당 주소를 가지고 플래그 를 획득해야 한다.

 

주소를 클릭하면 위 화면이 뜨는 것을 확인할 수 있으며 다른 방법으로 해당 주소에 접속해야 플래그를 획득할 수 있다는 것을 알 수 있다.

‘more [파일명]’ 명령어를 이용하여 해당 c 소스 코드 파일 내용을 확인했고 해당되는 파일 (?)로 들어갔을 때 flag 값이 출력되는 것을 확인할 수 있다.

접속 정보 보기를 통해 얻은 서버 주소를 입력한 결과 flag 값을 얻을 수 있었다.