Dreamhack(pwnable) - sint

oolongeya

·

2021. 9. 1. 18:45

sint.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
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
 
void alarm_handler()
{
    puts("TIME OUT");
    exit(-1);
}
 
void initialize()
{
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);
 
    signal(SIGALRM, alarm_handler);
    alarm(30);
}
 
void get_shell()
{
    system("/bin/sh");
}
 
int main()
{
    char buf[256];
    int size;
 
    initialize();
 
    signal(SIGSEGV, get_shell);
 
    printf("Size: ");
    scanf("%d"&size);
 
    if (size > 256 || size < 0)
    {
        printf("Buffer Overflow!\n");
        exit(0);
    }
 
    printf("Data: ");
    read(0, buf, size - 1);
 
    return 0;
}
cs

파일은 32비트 ELF 파일이다.

get_shell() 함수를 실행하는 것이 목적이다. get_shell() 함수는 system("/bin/sh"); 코드가 있는데, 쉘을 실행하는 것이다. 따라서 get_shell() 함수를 실행할 수 있다면 플래그를 얻을 수 있다.

 

char buf[256], size 순서대로 변수가 선언되고, signal(SIGSEGV, get_shell) 코드가 보인다.

Size의 값을 먼저 input으로 받는데, 이때 size의 값이 256보다 크거나 0보다 작으면 Buffer Overflow!\n를 출력한다

exit(0); 문이 있는 것으로 보아 이 조건문이 참이 되면 안되는 것이다.

 

input값을 다르게 했더니 위와 같이 나왔다.

그렇다면 get_shell의 주소를 확인한 뒤 size에서 ret까지의 거리를 계산해서 페이로드를 작성하면 되는걸까?

 

하지만 size 변수의 input을 받은 뒤 바로 뒤 조건문 있으니 긴 코드로 ret에 원하는 주소를 넣을 수 없다.

즉 패턴을 만들어서 확인할 수가 없기때문에 직접 메인함수의 assembly 코드를 보자.

 

 

0x104 바이트를 sub하는 것을 확인할 수 있다.

ret - sfp(ebp) - buf 순으로 쌓여있을 것이니,

0x104(바이트) + sfp(4바이트) => ret값

0x104는 10진수로 260이다 즉 264바이트 패딩 이후 ret값에 들어가고 여기에 get_shell() 함수의 주소가 들어가면 된다.

 

하지만! 이 값은 조건문에 걸려버린다. 중간 조건문에 걸리면 프로그램이 종료가 되니 조건문을 무조건 지나야한다.

 

즉 size에 알맞은 값을 넣어서 조건문을 통과한 뒤 read 함수 부분에서 승부를 봐야 한다.

 

read(0, buf, size - 1);

 

위와 같은 read 함수는 무엇을 의미하냐면,

 

size - 1 만큼의 크기를 파일에서 읽어서 buf에 저장한다고 생각하면된다.

size - 1 부분은 파일에서 얼마를 읽을지 적는 부분이다. 이때 원래 파일의 크기보다 더 크게 적게되면 파일의 내용 전부를 저장할 수 있게된다.

 

하지만 size의 값은 256보다 크거나 0보다 작아선 안된다.

 

따라서 size의 값은 0이다.

0은 조건문에 걸리지않지만 0-1의 경우 FFFF FFFF FFFF FFFF 가 되어버린다. 이 정도 크기면 엄청나게 큰 수이고, 

read 함수에서 사용하면 파일의 모든 정보를 읽을 수 있을 것이다.

 

따라서 첫 번째 input에서 0을 입력하고 두 번째 input에서 패딩값 + get_shell() 함수 주소로 페이로드를 구성할 수 있다.

 

get_shell 함수의 주소를 확인한다.

 

 

얻은 정보들과 내용으로 작성한 코드이다.

실행하면 

성공적으로 플래그를 얻을 수 있다.

반응형