1. #include <stdio.h>  
  2. #include <fcntl.h>  
  3. int key1(){  
  4.     asm("mov r3, pc\n");  
  5. }  
  6. int key2(){  
  7.     asm(  
  8.     "push   {r6}\n"  
  9.     "add    r6, pc, $1\n"  
  10.     "bx r6\n"  
  11.     ".code   16\n"  
  12.     "mov    r3, pc\n"  
  13.     "add    r3, $0x4\n"  
  14.     "push   {r3}\n"  
  15.     "pop    {pc}\n"  
  16.     ".code  32\n"  
  17.     "pop    {r6}\n"  
  18.     );  
  19. }  
  20. int key3(){  
  21.     asm("mov r3, lr\n");  
  22. }  
  23. int main(){  
  24.     int key=0;  
  25.     printf("Daddy has very strong arm! : ");  
  26.     scanf("%d", &key);  
  27.     if( (key1()+key2()+key3()) == key ){  
  28.         printf("Congratz!\n");  
  29.         int fd = open("flag", O_RDONLY);  
  30.         char buf[100];  
  31.         int r = read(fd, buf, 100);  
  32.         write(0, buf, r);  
  33.     }  
  34.     else{  
  1.         printf("I have strong leg :P\n");  
  2.     }  
  3.     return 0;  
  4. }  

r0? r3? 
레지스터를 보아하니 ARM 이다.

문제를 보면 key1 + key2 + key3 == 입력값 이면 flag를 출력한다.
어셈을 보면서 하나하나 따라가보자


ARM에서 pc(program counter)의 값이r0에 남는다.


r0는 return값이 들어간다.


program counter에는 다음에 실행할 명령어의 주소가 들어있다.


즉 pc는 사용된 주소 +4byte를 가지므로 


key1에는 다음 명령어가 실행될 주소인 8ce4가 된다.



pc의 값을 r3에 넣고 를 더해주는 것을 확인할 수 있다.


그렇다면 8d04 + 4 + 4 == 8d0c가 key2의 값이 된다.



lr을 r3에 넣고 r3을 r0에 넣는것을 확인할 수 있다.


lr은 함수 호출시 리턴될 값을 의미한다.


main함수를 따라가보자.



key3은 8d80이 된다.


key1 + key2 + key3 = key이고 정수를 인자로 받으므로 key=108400



앙기모띠

'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -cmd1  (0) 2016.09.25
pwnable.kr -lotto  (0) 2016.09.25
pwnable.kr -random  (0) 2016.09.25
pwnable.kr -passcode  (0) 2016.09.24
pwnable.kr -echo1  (0) 2016.09.23
  1. int main(){  
  2.     unsigned int random;  
  3.     random = rand();    // random value!  
  4.   
  5.     unsigned int key=0;  
  6.     scanf("%d", &key);  
  7.   
  8.     if( (key ^ random) == 0xdeadbeef ){  
  9.         printf("Good!\n");  
  10.         system("/bin/cat flag");  
  11.         return 0;  
  12.     }  
  13.   
  14.     printf("Wrong, maybe you should try 2^32 cases.\n");  
  15.     return 0;  
  16. }  


key값과 random 을 XOR 연산을 하였을때 0xdeadbeef 가 나오면 된다.


random 시드가 없으므로 값이 고정되어 있을 것이다.


random값은 rand 함수가 실행된 다음에 저장될 것이다.



필자는 scanf ( )함수가 시작되기 전의 주소에 break point를 걸고 실행시켰다.

random 값은 rbp -0x4에 있으며 그 값은 0x6b8b4567이다.


a^b=c

c^b=a


XOR의 특징을 이용하여 키를 구한다.



key는 3039230856이다.

scanf( )가 정수를 취하므로 굳이 바꿀 필요 없겟다 그대로 대입하자.



앙 기모띠

'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -lotto  (0) 2016.09.25
pwnable.kr -leg  (0) 2016.09.25
pwnable.kr -passcode  (0) 2016.09.24
pwnable.kr -echo1  (0) 2016.09.23
pwnable.kr -bof  (0) 2016.07.29
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. void login(){  
  5.     int passcode1;  
  6.     int passcode2;  
  7.   
  8.     printf("enter passcode1 : ");  
  9.     scanf("%d", passcode1);  
  10.     fflush(stdin);  
  11.   
  12.     printf("enter passcode2 : ");  
  13.         scanf("%d", passcode2);  
  14.   
  15.     printf("checking...\n");  
  16.     if(passcode1==338150 && passcode2==13371337){  
  17.                 printf("Login OK!\n");  
  18.                 system("/bin/cat flag");  
  19.         }  
  20.         else{  
  21.                 printf("Login Failed!\n");  
  22.         exit(0);  
  23.         }  
  24. }  
  25.   
  26. void welcome(){  
  27.     char name[100];  
  28.     printf("enter you name : ");  
  29.     scanf("%100s", name);  
  30.     printf("Welcome %s!\n", name);  
  31. }  
  32.   
  33. int main(){  
  34.     printf("Toddler's Secure Login System 1.0 beta.\n");  
  35.   
  36.     welcome();  
  37.     login();  
  38.   
  39.     // something after login...  
  40.     printf("Now I can safely trust you that you have credential :)\n");  
  41.     return 0;     
  42. }  



코드를 보면 main( ) -> welcome( ) -> login( ) 순으로 흘러간다.


welcome( ) 함수를 살펴보면 name 배열에 100byte를 입력받고 그것을 인자로 출력한다. login( )함수에서는 2개의 입력받을 받아 출력하는데 


scanf( )함수에 &가 없다.

또한 fflush(stdin)을 통해 버퍼를 비운다.


우리가 여기서 알고 가야할 점은

scanf( ) 는 &가 없으면 받은 인자를 주소로 인식한다.


gdb를 통해 분석해보자.



다음은 welcome을 disassembly 한 모습이다.

scanf( ) 가 실행되고 입력을 받은 이후를 봐야 하므로 실행이 된 이후 임의의 지점에 break point를 걸어준다. 필자는 0x804864d에 걸어주었다.



96byte 뒤의 주소를 덮어 씌울 수 있다.


그렇다면 원하는 곳의 4byte를 입력할 수 있다.


fflush(stdin)을 우회하기 위해 fflush의 got를 overwrite 한다.


이후 system("/bin/cat flag") 로 점프하면 플래그가 나올 것 같다.



exit( )함수를 사용할 것이므로 info function 명령어를 통해 exit( ) 함수의 주소를 알 수 있다.  exit( ) 함수의 주소는 0x08048480이다.



exit( ) 함수의 got 는 0x804a018이다.


/bin/cat flag 의 주소는 0x080485e3 이다.


페이로드를 작성하면

buffer(96) + exit@got + 0x080485e3의 10진수 + "\n" + "asdfasdf" + "\n"

이정도가 될것이다


10진수를 취하는 이유는 scanf가 %d , 즉 정수를 인자로 받기 때문이다.



앙 기모띠

'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -leg  (0) 2016.09.25
pwnable.kr -random  (0) 2016.09.25
pwnable.kr -echo1  (0) 2016.09.23
pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -flag  (0) 2016.07.15

bof


버퍼 오버플로우 문제이다 평상시 공부했던것 처럼 풀면 되나....


약간의 문제가 있어보인다!


확인해보자


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
	char overflowme[32];
	printf("overflow me : ");
	gets(overflowme);	// smash me!
	if(key == 0xcafebabe){
		system("/bin/sh");
	}
	else{
		printf("Nah..\n");
	}
}
int main(int argc, char* argv[]){
	func(0xdeadbeef);
	return 0;
}

overflowme 라는 배열이 32byte로 선언되어 있다.


그리고 gets ( )함수를 통해 입력받아 그 값이 0xcafebabe 이면 쉘을 얻어낼 수 있다.


기본값은 0xdeadbeef 으로 선언되어있다.


우리는 하던대로 배열 32byte를 덮어씌우고 func의 주소를 찾아 deadbeef를 cafebabe로 바꾸면 쉘을 딸 수 있다.


실행해보자. 



WOW 보호기법중 하나인 카나리가 걸려있다.


그렇다면 우리는 스택의 주소를 참조하여 어디에 deadbeef 라는 값이 들어가 있는지 찾으면 될것 같다. 자 분석해보자.



disas func 명령어를 통해 func 함수를 디스어셈블리 한 내용이다.


자세히 보면 0x5655564f 에서 gets 함수를 통해 입력을 받고

0x5655565d 에서 jne 명령어를 통해 분기된다.


그렇다면 gets 함수 다음에 바로 break 문을 걸고 실행을 시킨후 스택을 보면 덮이는 부분을 확인할 수 있을 것 같다.



버퍼 오버플로우 공격을 실행하면 분명히 stack이 덮일것이다 확인해보자.




자 두번째 끝에부터 0x41414141로 덮였다.


보이는가 0xdeadbeef 가!!!!


우리는 저 부분을 0xcafebabe 로 바꿔주면 되는것 아닌가!!!


자 바꿔주자 저부분 전까지 덮어주려면 12byte 만큼을 더 덮어주면 된다.


그렇다면 공격코드는 다음과 같다.


(python -c 'print "A"*52 + "\xbe\xba\xfe\xca")


공격을 시도할 땐 nc로 payload를 보내보자


(python -c 'print "A" * 52 + "\xbe\xba\xfe\xca" + "\n"' ; cat) | nc pwnable.kr 9000



'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -passcode  (0) 2016.09.24
pwnable.kr -echo1  (0) 2016.09.23
pwnable.kr -flag  (0) 2016.07.15
pwnable.kr -shellshock  (0) 2016.07.15
pwnable.kr -mistake  (0) 2016.07.15


flag 파일의 확장자를 알 수 없어 

Hex-Ray를 통해 출력시켜보았다.




ELF 바이너리 파일 같은데 밑에 내려보면 UPX! 라는 문구로 보아


UPX 로 패킹되어 있음을 알 수 있었다.


먼저 패킹을 풀어주도록 하자.








시그니처에 UPX 가 사라진 것으로 보아 언패킹에 성공했다는 것을 알 수 있다.


확장자가 ELF 인 것으로보아 바이너리 파일 임을 짐작할 수 있고 이제 이 파일을 헥스레이인 IDA를 이용하여 분석해보자.




IDA에서 main 함수를 찾은 뒤 소스를 확인해보면



flag 라는 값을 볼 수 있을 것이다 더블클릭하여 이 부분을 살펴보면



짜잔! 하고 플래그가 나타나게 된다.


'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -echo1  (0) 2016.09.23
pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -shellshock  (0) 2016.07.15
pwnable.kr -mistake  (0) 2016.07.15
toddler -collision  (0) 2016.07.15


문제의 소스코드는 다음과 같다.




소스코드를 보면 권한 상승후 system함수를 실행하고 있다는 것을 알 수 있다.


또한 line 5를 잘 보면 shellshock 취약점이 존재한다는 것을 알 수 있다.


shellshock는 환경변수를 통한 코드 인젝션이 가능한 취약점이다.


bash의 환경 변수에 함수정의를 이용해서 원하는 코드를 추가할 수 있고 , 다음 bash가 사용될 때 추가된 코드가 실행되는 취약점이다. 


즉 함수정의 뒤에 임의의 명령을 추가하면 bash 는 환경변수를 import할때 끝에 추가된 명령까지 같이 실행하게 된다. 


이를 이용하여 test라는 환경변수에 함수정의를 이용하여 /bin/cat flag 라는 명령을 추가한 후 shellshock 프로그램을 실행해보자.



공격이 제대로 실행되었다.

'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -flag  (0) 2016.07.15
pwnable.kr -mistake  (0) 2016.07.15
toddler -collision  (0) 2016.07.15
toddler -fd  (0) 2016.07.13

mistake.c 의 소스코드를 열어보면 다음과 같다.


#include <stdio.h>

#include <fcntl.h>


#define PW_LEN 10

#define XORKEY 1


void xor(char* s, int len){

int i;

for(i=0; i<len; i++){

s[i] ^= XORKEY;

}

}


int main(int argc, char* argv[]){

int fd;

if(fd=open("/home/mistake/password",O_RDONLY,0400) < 0){

printf("can't open password %d\n", fd);

return 0;

}


printf("do not bruteforce...\n");

sleep(time(0)%20);


char pw_buf[PW_LEN+1];

int len;

if(!(len=read(fd,pw_buf,PW_LEN) > 0)){

printf("read error\n");

close(fd);

return 0;

}


char pw_buf2[PW_LEN+1];

printf("input password : ");

scanf("%10s", pw_buf2);


// xor your input

xor(pw_buf2, 10);


if(!strncmp(pw_buf, pw_buf2, PW_LEN)){

printf("Password OK\n");

system("/bin/cat flag\n");

}

else{

printf("Wrong Password\n");

}


close(fd);

return 0;

}


소스코드를 해석하자면


처음에 입력한 10byte 값과 두번째로 입력된 10byte를 XOR 연산한다.


연산한 결과값이 처음에 입력한 값과 같다면 /bin/cat/flag 를 출력한다.


소스코드를 분석할 줄 알면 아주 간단한 문제이다.


동시에 C언어에 대해 얼마나 깊게 이해하고 있는지를 묻는 아주 재미있는 문제이다.


XOR 연산의 특징은


--------------------

A xor B

0      0 = 0

0      1 = 1

1      0 = 1

1      1 = 0

--------------------


두개의 값이 반전일 경우 1을 출력하고 두개의 값이 같을경우에는 0을 출력한다.


첫번째 10바이트와 두번째 10바이트 수를 XOR 해서 처음 수가 나와야 한다면


1111111111

0000000000


을 연산하게 되면 1111111111 처음 값이 나오게 된다.



개인적으로 이런 문제를 아주 좋아한다.


'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -flag  (0) 2016.07.15
pwnable.kr -shellshock  (0) 2016.07.15
toddler -collision  (0) 2016.07.15
toddler -fd  (0) 2016.07.13

col.c 의 소스코드를 보면 다음과 같다.



20byte passcode를 인자로 받는다.


check_password() 함수를 참고하면 입력받은 값을 4byte 씩 5번 입력받아


res 변수에 누적된다.


우리는 누적된 값을 0x21DD09EC로 맞춰주면 된다.


먼저 0x21DD09EC를 5로 나누어 보면 0x06C5CEC8 이다.


하지만 0x21DD09EC는 5로 나누었을때 나머지가 4 이므로


0x06C5CEC8 x 4 + (0x06C5CEC8 + 4) = 0x21DD09EC 가 된다. 


이제 이걸 인자로 쳐 넣어주면 된다.





'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -flag  (0) 2016.07.15
pwnable.kr -shellshock  (0) 2016.07.15
pwnable.kr -mistake  (0) 2016.07.15
toddler -fd  (0) 2016.07.13

ssh fd@pwnable.kr p2222 에 접속하면 fd.c 의 C언어 소스코드가 있다. 



argv[1]에 어떠한 값을 넣어야 하고 그 값은 0x1234이다


atoi()함수가 있는것으로 보아 0x1234를 정수로 넘겨줘야 할것 같다.


또한 strcmp()함수로 "LETMEWIN"이라는 문자열을 비교하여


맞으면 /bin/cat/flag를 통해 플래그를 출력한다.


자 이제 집어 넣어보자


flag가 정상적으로 출력되었음을 확인할 수 있다.

'pwnable > pwnable.kr' 카테고리의 다른 글

pwnable.kr -bof  (0) 2016.07.29
pwnable.kr -flag  (0) 2016.07.15
pwnable.kr -shellshock  (0) 2016.07.15
pwnable.kr -mistake  (0) 2016.07.15
toddler -collision  (0) 2016.07.15

+ Recent posts