코드가 평소보다 길어서 당황했지만 분석을 해보자면
void형의 shellout 함수, int형의 main 함수가 선언되어 있다.
shellout 함수는 setuid 함수로 level19 권한으로 바꿔주며 배쉬 쉘을 실행시키는 역할을 한다.
mainf 함수에는 char형의 100byte 리스트 string, int형의 check/ x/ count, fd_set 구조체 fds가 선언되어 있고,
x와 count는 0으로 초기값이 초기화 되어 있다.
if 문을 통해 count가 100 이상일 경우 "what are you trying to do" 를 출력하여 이상한 동작임을 알려준다.
if 문을 통해 check의 값이 0xdeadbeef일 경우 shellcout() 함수로 쉘을 실행한다.
나는 shellcout을 실행시켜야 하므로 check의 값을 0xdeadbeef로 만들어야 한다.
check의 값이 0xdeadbeef가 아닐 경우에는 else로 넘어간다.
받아온 입력값에서 1byte를 가져온다.
그 값이 0x08이면 count를 -1하고 아니라면 string[count]에 그 값을 대입한 후에 count를 +1한다.
* fd_set 구조체
- FD를 저장하는 구조체
- FD: File Descriptor의 줄임 표현이며 자신이 사용할 파일/ 장치에 대한 고유한 식별값
- __FD_SERSIZE: #define을 사용하여 1024 값을 치환한 상수 값, FD 집합의 크기를 나타냄
- __fd_mask: typedef를 사용하여 정의하며 int long과 동일하게 4byte, 특정 비트 값을 제거하거나 체크할 때 사용
- __NFDBITS: 8*(int)로 정의되어 있기 때문에 32byte
- FD_SET( ): set에 FD를 추가할 때 사용
- FD_ZERO( ): fd_set으로 선언된 변수를 초기화할 때 사용, 모든 변수의 비트 값을 0으로 설정
- FD_CLR( ): FD_SET 함수를 사용하여 추가했던 FD 값을 rfds 변수에서 제거할 때 사용, 해당 비트 값을 0으로
- FD_ISSET( ): fd_set으로 선언된 변수의 특정 FD 값이 어떻게 설정되어 있는지 확인할 때 사용
* select
- int select ( int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct tiemval *timeout )
- ndfs / 감시할 파일 디스크립터의 갯수, 마지막 파일 디스크립터 번호에 +1을 지정 (index가 0부터 시작)
- readfds / 읽을 데이터가 있는지 감시하는 파일의 집합
- writefds / 파일에 데이터를 쓸 수 있는지를 검사하기 위한 파일 집합
- exceptfds / 파일의 예외 사항이 있는지 검사하기 위한 파일 집합
- timeout / 데이터의 변화를 감지하기 위해 사용하는 time out 값, 성공시 fd의 갯수를 반환함
지정된 시간동안 읽을 데이터가 없다면 0 반환, timeout을 NULL로 지정하면 무기한으로 대기함
파일을 분석하기 위해 tmp 디렉토리로 복사하고 ls 명령어로 확인하였다.
<main+3>을 보면 0x100(256byte)를 할당했다.
<main+12> <main+19>에서 변수를 0으로 초기화 하므로 이는 x(0xffffff94)와 count(0xffffff90) 이다.
<main+91> 에서 check와 0xdeadbeef의 값을 확인한다. check의 값은 0xffffff98이다.
각각이 4byte고 연속된 주소 값을 가지므로 그 사이에 dummy가 존재하지 않는 것을 알았다.
[ 메모리 구조 ]
RET // 4byte
SFB // 4byte
string // 100byte
check // 4byte 0xffffff98
x // 4byte 0xffffff94
count // 4byte 0xffffff90
shellout 함수를 실행하기 위해서는 check에 beadbeef를 넣어야 하는데
check가 string보다 낮은 주소값을 가지기 때문에 지금까지 사용했던 버퍼오버플로우로는 안된다.
main 함수 안에 있는 스위치 문을 사용해서 count 값을 감소시켜 string[-1]이 작동되게 해야 한다.
check는 4byte 이고 사이에 더미가 존재하지 않으므로 4만큼 -1을 하면 된다.
count--를 하기 위해서는 값이 0x08이여야 한다.
이를 이용하여 페이로드를 작성하면
[ 페이로드 ]
"\x08" * 4 + "\xef\xbe\xad\xde"
command를 작성하라고 나와서 당황했지만 원래대로 입력하니 작동했다.
fd_set을 이해하지 못하면 못 푸는 문제라고 생각해서 이걸 찾아보고 이해하는데
시간이 많이 걸렸는데 풀다보니 그런 문제는 아니더라.
level19의 패스워드는 " swimming in pink "