목록CTF Write-up (9)
cgy12306
Screw driver와 함께 출제었던 windows kernel exploit 문제입니다. Anna라는 친구가 크리스마스 소원을 적은 일기장을 부모님이 Anna가 자는 사이 몰래 읽어야 성공하는 컨셉의 문제였습니다. 난이도 조절한다고 낑낑대면서 낸 문제였는데 0 Solve여서 놀림을 많이 받았습니다ㅠㅠㅠ lpe가 되는지 직접 검수해야 돼서 라이트업을 받아 결과를 메일로 답을 줘야 했기 때문에 답변용 메일도 작성해놨었는데 아쉽게도 제출한 사람이 없어 폐기처분해야 했습니다. 아마 0 solve인 이유는 윈도우 포너블을 하는 사람이 별로 없어서라고 생각하고 있습니다.... 혼자 올클 방지용 문제라 위로 중...ㅎㅎ dispatchDeviceControl을 보게 되면 3개의 ioctl 코드로 분기를 나누고 있..
제가 처음으로 CTF에 출제한 문제입니다. Best of Best 프로젝트 기간중에 윈도우 드라이버 코딩도 해보고, 거의 매일 밥먹듯이 드라이버 리버싱을 하다보니 드라이버 문제를 내면 많은 사람들이 드라이버에 대해 조금이라도 알아 가실 수 있지 않을까해서 문제 출제를 결심하게 되었습니다. 대회가 종료되고 드림핵에 라이트업을 작성해서 냈지만 너무 간략하게 적은것 같아서 블로그에 다시 작성해봅니다. driver entry를 보게 되면 device name은 screw로 설정되어 있습니다. MajorFunction의 14번째 핸들러인 sub_140002F10로 DeviceIoContorl을 통해 kernel과 통신을 할 수 있습니다. sub_140002F10 함수를 살펴보겠습니다. v4 변수는 IOCTL을 담..
dart-mast 바이너리를 아이다로 분석해보자. 후... C++로 되어있다... C++ 공부를 많이 해야될듯하다. 1번을 입력해서 Login과정을 거치고 v11에 0x40만큼 동적할당 해준다. sub_19B0(make_vtable)에 v11을 인자로 넣어서 호출한다. sub_1360은 단순히 초기화 하는 함수이다. v11에 vtable + 2와 연결한다. 즉 v11배열에 저 주소들이 들어가게 된다. v11[0] = 로그인 v11[1] = 내부 v11[2] = 가입 v11[3] = 모드선택 v11[4] = 연습 v11[5] = 찐게임 이렇게 들어가게 된다. v11[6]에 8byte만큼 동적할당해주고 0으로 초기화한다. login하고, See others information을 선택해서, Card ID를 ..
이번 문제를 ubuntu 18 환경에서 하면 안된다고한다... 이것때문에 오랜 시간이 걸렸다. ubuntu 16 환경에서 하도록하자.. 우선 바이너리를 분석하자. 처음에 스택 주소를 주고 1, 2, 3, 4, 5를 선택하도록 한다. 1을 선택했을 때 sub_4009E6에 v4를 인자로 넘기면서 호출한다. sub_4009E6을 호출했을 때 사이즈와 데이터를 입력받는다. 사이즈가 0봐 작거나 32이상일 경우 사이즈를 32로 동적할당을 받고 나머지 경우 해당 사이즈로 동적할당을 한다. 동적할당 된 주소는 a1(v4)의 빈 공간에 저장된다. 그리고 buf 변수에 데이터를 33만큼 받아온다. 이후 memcpy로 buf에 담긴 값을 a1(v4)에 담는다. 이제 2번을 눌렀을 때 호출되는 sub_400BFD를 들어가..
floppy 바이너리를 실행해보자. 살짝 유추해 보자면 1번을 선택했을 때 플로피를 선택하고, 2번은 쓰기, 3번 읽기, 4번 수정, 5번 종료 대충 이런 프로그램 같다. 보호기법을 확인해보자. NX bit, PIE가 설정 되어 있다. 아이다로 바이너리 분석해 보자. 처음에 1을 선택하게 되면 디스크를 선택해야 하는데 1번 또는 2번을 선택하게 된다. 이 선택한 번호에따라 v8 포인터에 v6가 연결될지 v7이 연결될지 결정된다. 스택상황을 그려보자. v6[24] | v7[24] | v8 | v9 | ? | ebp | ret sub_C5F는 2를 입력했을 때 들어가는 함수이다. *(v7 + 4)에는 data의 동적할당 된 주소가 들어가 있고, *(v7+20)에는 입력한 길이가 들어간다. *(v8 + 8)에..
바이너리를 IDA로 열어서 그래프로 보면 아래와 같이 많은 루틴들이 있는걸 볼 수 있다. 우선 실행시켜보자. 아무런 응답이 없다. 그 이유는 스택 카나리 값을 rax에 넣고, 자기자신과 xor 연산한 다음 0이면 exit 하는 함수로 보내버리기 때문이다. 우리가 도착해야 할 지점은 0x404FAB이다. 하지만 exit로 바로 빠져나가기 때문에 hex editor로 코드를 변조해야 할 듯 하다. jz _exit를 nop(0x90)으로 바꾸고 다시 실행해보자. gdb에 심볼이 없기 때문에 init에 breakpoint를 걸고 다시 vmmap으로 메인에 breakpoint를 걸어서 확인해보자. 4077b에 명령어가 있다. 어떤 값이 들어가는지 확인하고 0x90으로 바꾸자 다음 명령어를 건들면 안되기 때문에 0..
해당 파일을 IDA로 열어서 분석 해봤다. 인자를 3개를 받는데 첫번째 인자는 정수, 두번째 인자는 문자열, 세번째 인자는 아무값이나 받는다. 첫번째 인자가 1을 넘어야 하고, 두번째 인자의 길이를 재서 sub_1273함수로 보낸다. sub_1273은 인자를 두개 받는데 문자열과, 문자열의 길이를 받는다. 만약 반환값이 0이 되면 올바른 password가 된다. sub_1273을 분석해보자. 넘겨받은 문자열의 길이만큼 반복을 하게 되는데 off_43E0에 있는 i번째 위치에 있는 값과 문자열의 길이만큼 xor 연산을 하고 문자열의 i번째에 있는 값을 다시 xor 연산한 후 해당 결과값을 or 연산해서 v3 변수에 넣는다. v3 변수를 반환하게 되는데 그 값이 0이어야 된다. or은 두개의 바이너리 값 중..
IDA로 바이너리를 분석해보자. off_202010이 있는 값을 qword_202060[29]에 넣는다. off_202010에는 printf 함수에 대한 정보를 갖고 있다. getchar로 입력받은 값이 문자 '1'이이 아니면 break로 반복문을 빠져 나오고, 문자 '2'이면 다시 반복문을 빠져나온다. setjmp 함수는 호출 당하기 전의 스택 상황을 환경 변수에 저장 했다가 longjmp 함수가 호출되면 환경 변수에 저장해놨던 값을 다시 불러온다. setjmp는 무조건 return 값을 0을 반환하기 때문에 !로 참을 만들어 줬다. 이후 sub_95A 함수를 호출한다. 인자로는 qword_202060을 넘긴다. sub_95A 함수의 내부이다. gets로 a1에 값을 받는다. a1의 문자열에 'n'이 ..