본문 바로가기

WARGAME/smch ctf

SMCH CTF - Calc

 

 

문제는 다음과 같다. 이번에도 바이너리 대신 소스 코드를 다운 받도록 되어 있당 코드를 다운 받아 보면,

 

 

 

 

 

 

calc.c라는 이름의 C언어 소스 코드 파일을 받을 수 있다. calc.c 소스코드의 내용은 다음과 같당

 

 

 

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
 
int cnt;
 
void get_flag(){
    puts("Congratz!");
    system("cat flag");
}
 
void intro(){
    setvbuf(stdin,0,2,0);
    setvbuf(stdout,0,2,0);
    srand(time(NULL));
    puts("=== simple calc ===");
    puts("you will need a calculator to solve this prob");
    puts("simple rule : just solve the problem");
    puts("there are 4 operators, +:add -:sub *:mul /:div");
    puts("ex: prob ]add 5 10");
    puts("    ans ]15");
    puts("ex: prob ]mul 2 23");
    puts("    ans ]46");
    puts("if you solve 100 probs, I will give you flag!");
    puts("*********** U only have 30 seconds *************");
}
 
void end_alarm(){
    puts("Time up! U must be v3ry v3ry qu1ck");
    exit(0);
}
 
int prob(){
    int a,b,ans,inp=0xFFFFFFFF;
    char op[4]={0,};
AA:
    a=rand()%45000;
    b=rand()%45000;
    switch(rand()%4){
        case 0:
            strcat(op,"add");
            ans=a+b;
            break;
        case 1:
            strcat(op,"mul");
            ans=a*b;
            break;
        case 2:
            strcat(op,"div");
            b=rand()%10+1;
            ans=a/b;
            break;
        case 3:
            strcat(op,"sub");
            if(a-b==-1)goto AA;
            ans=a-b;
    }
    printf("prob >%s %d %d\nans :",op,a,b);
    scanf("%d"&inp);
    if(inp==ans){
        puts("Y34h!");
        return 1;
    }
    puts("Seriously?");
    return 0;
}
 
int main(){
    signal(SIGALRM, end_alarm);
    alarm(30);
    intro();
    while(1){
        printf("\n\nYou solved %d problems\n",cnt);
        if(cnt>=100){
            get_flag();
            exit(0);
        }
        cnt += prob();
    }
    exit(0);
    return 0;
}

 

 

 

소스코드를 보면 메인 함수에서 cnt가 100보다 크거나 같을 때 까지 반복문을 돌리고 cnt가 100 전까지는 계속 prob라는 함수를 호출한당

prob함수에서는 a, b변수에 난수를 넣고 또 switch문에서 rand % 4를하여 난수 % 4한 값에 따라 "add", "mul", "div", "sub"문자열을 op 배열에다가 넣고, a, b를 더하거나 빼거나 곱하거나 나눈 값을 ans라는 변수에다 넣는다. 그리고 printf함수를 통해 op에 들어간 문자열과 a, b 변수의 값을 출력한다. 이후, 사용자로부터 inp라는 변수에다가 정수형 데이터를 입력 받고 이전의 ans와 비교를 해서 같으면 1을 리턴하여 메인함수에서는 리턴된 1을 cnt에다가 더하는 방식이다. 즉 a, b에다가 난수 10과 30이 들어가고 switch문에서 난수 % 4 한 값이 0이면 10과 30을 더한 값을 ans에다가 넣고 printf로 prob >add 10 30를 출력해주어 사용자가 10 + 30인 40을 입력으로 넣어주면 ans와 비교해 둘이 같으면 1을 리턴해주는 형식이다. 이번 문제는 이전 문제와는 다르게 손수 계산을 하지 못하도록 30초가 지나면 강제적으로 프로그램이 종료되게 되어 있다. 이번 문제도 pwntools를 활용하면 될 거 같당 우선 직접 소스 코드를 컴파일해 실행시켜보면,

 

 

 

 

 

요렇게 앞서 말했던 것 처럼 사칙연산중 한가지와 난수 두개가 출력되면서 계산한 값을 입력하라고 한당. 또 입력한 값이 참이면, 

"You solved 1 problems" 라는 문자열과 함께 한 번더 입력을 받을 수 있게 된다. 문제를 해결할 방식을 생각해보면, 우선

recvuntil 함수로 "prob >" 까지 받고 버린다음 그 뒤에 있는 값들을 data = p.recvuntil("\n")[:-1]로  "\n" 개행 전까지 받는다.

 

그럼 저 첫 번째 예시 같은 경우로면 data에 "sub 28041 5265"가 담길 거고 이제 이 값들을 "sub", "28041", "5265"로 나누어서 연산을 하면 될 것이다. 파이썬에는 split이라는 편리한 함수가 있으므로 data2 = data.split(" ")을 통해 공백별로 문자열을 쪼개 data2에 리스트의 형태로 넣는다. 위 과정을 통해 data2에는 ['sub','28041','5265']로 나누어 담길 거고 data2[0]이 "add"면 data[1](20841) + data2[2](5265)연산한 값을 snedline함수로 보내주면 될 것이다. 마찬가지로 data2[0]이 "sub"거나 "div"혹은 "mul"이면 그에 맞는 연산을 진행하여 보내면 될 것이다. 

 

 

 

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
from pwn import*
 
= 0
 
p=remote("ssh.luxroot.com"9007)
 
while i<100:
 
    p.recvuntil("prob >")
    data = p.recvuntil("\n")[:-1]
 
    data2=data.split(" ")
 
    if data2[0]=="add":
        p.sendline(str(int(data2[1])+int(data2[2])))
    elif data2[0]=="sub":
        p.sendline(str(int(data2[1])-int(data2[2])))
    elif data2[0]=="mul":
        p.sendline(str(int(data2[1])*int(data2[2])))
    elif data2[0]=="div":
        p.sendline(str(int(data2[1])/int(data2[2])))
    i=i+1
 
p.interactive()
 
 

 

 

 

다음과 같이 익스를 짜고 실행시켜보면,

 

 

 

 

flag를 딸 수 있당

 

FLAG : flag{U_R_S0ck3t_Pr09ramm1n9_G0D}

'WARGAME > smch ctf' 카테고리의 다른 글

SMCH CTF - BOF_ret  (0) 2019.11.09
SMCH CTF - Rock Paper scissors(EZ)  (0) 2019.11.08
SMCH CTF - BOF4  (0) 2019.11.08
SHCH CTF - BOF3  (0) 2019.11.03
SMCH CTF - BOF2 (EZ)  (0) 2019.11.03