본문 바로가기

Wargame/Bandit

[ Docker ] Bandit Wargame 만들기 - 24번 문제 ( 25 / 33 )

1. Bandit24 목표

A daemon is listening on port 30002 and will give you the password for bandit25 if given the password for bandit24 and a secret numeric 4-digit pincode.
There is no way to retrieve the pincode except by going through all of the 10000 combinations, called brute-forcing.
You do not need to create new connections each time

 

2. Bandit24 구현

# 비밀번호 root 입력 접속
ssh -oStrictHostKeyChecking=no root@localhost -p 2220

chown -R root:root /home/bandit24/.[!.]*

cat <<'BANDIT_TMP' > /tmp/bandit25_answer.c
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "time.h"
#include "sys/types.h"
#include "sys/socket.h"
#include "netinet/in.h"
#include "arpa/inet.h"
#include "unistd.h"
#include "signal.h"

#define BUF_LEN 128

char *read_file_content(const char *file_path)
{
    FILE *file;
    char *buffer;
    long file_size;

    file = fopen(file_path, "r");
    if (file == NULL)
    {
        perror("Error opening file");
        return NULL;
    }

    fseek(file, 0, SEEK_END);
    file_size = ftell(file);
    rewind(file);

    buffer = (char *)malloc(sizeof(char) * (file_size + 1));
    if (buffer == NULL)
    {
        perror("Memory allocation failed");
        fclose(file);
        return NULL;
    }

    size_t read_size = fread(buffer, sizeof(char), file_size, file);
    if (read_size != file_size)
    {
        perror("Error reading file");
        free(buffer);
        fclose(file);
        return NULL;
    }

    buffer[file_size] = '\0';

    fclose(file);

    if (buffer[file_size - 1] == '\n') {
        buffer[file_size - 1] = '\0';
    }

    return buffer;
}

char *concatenate_strings(const char *str1, const char *str2)
{
    size_t len1 = strlen(str1);
    size_t len2 = strlen(str2);
    char *new_content = (char *)malloc(len1 + len2 + 1);
    if (new_content == NULL) {
        perror("Memory allocation failed");
        return NULL;
    }

    memcpy(new_content, str1, len1);
    memcpy(new_content + len1, str2, len2 + 1);

    return new_content;
}

int main(int argc, char *argv[])
{
    signal(SIGPIPE, SIG_IGN);

    char buffer[BUF_LEN];
    struct sockaddr_in server_addr, client_addr;
    char temp[20];
    int server_fd, client_fd;

    socklen_t len;
    ssize_t msg_size;

    char *answer = read_file_content("/etc/bandit_pass/bandit24");
    if (answer == NULL)
    {
        fprintf(stderr, "Failed to read file content.\n");
        return EXIT_FAILURE;
    }

    const char *additional_string = " 1452";

    char *new_answer = concatenate_strings(answer, additional_string);
    if (new_answer == NULL)
    {
        free(answer);
        return EXIT_FAILURE;
    }

    free(answer);

    if(argc != 2)
    {
        printf("usage : %s [port]\n", argv[0]);
        exit(0);
    }

    if((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("Server : Can't open stream socket");
        exit(1);
    }
    memset(&server_addr, 0x00, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    server_addr.sin_port = htons(atoi(argv[1]));

    if(bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        perror("Server : Can't bind local address");
        close(server_fd);
        exit(1);
    }

    if(listen(server_fd, 5) < 0)
    {
        perror("Server : Can't listen for connections");
        close(server_fd);
        exit(1);
    }

    printf("Server : waiting for connection request.\n");
    len = sizeof(client_addr);
    while(1)
    {
        client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &len);
        if(client_fd < 0)
        {
            perror("Server: accept failed");
            continue;
        }

        inet_ntop(AF_INET, &client_addr.sin_addr, temp, sizeof(temp));
        printf("Server : %s client connected.\n", temp);

        write(client_fd, "I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.\n", strlen("I am the pincode checker for user bandit25. Please enter the password for user bandit24 and the secret pincode on a single line, separated by a space.\n"));

        while (1) {
            msg_size = read(client_fd, buffer, BUF_LEN - 1);
            if(msg_size < 0)
            {
                perror("Server: read failed");
                break;
            } else if (msg_size == 0) {
                // Client disconnected
                printf("Client disconnected\n");
                break;
            }

            buffer[msg_size] = '\0';  // Ensure null-terminated string

            printf("Received %ld bytes: %s\n", msg_size, buffer);

            buffer[strcspn(buffer, "\n")] = '\0'; // Remove newline character if exists

            if(strcmp(buffer, new_answer) == 0)
            {
                char *nextPass = read_file_content("/etc/bandit_pass/bandit25");
                if (nextPass == NULL)
                {
                    fprintf(stderr, "Failed to read next file content.\n");
                    continue;
                }

                const char *message_template = "Correct!\nThe password of user bandit25 is %s\n\n";
                size_t message_size = snprintf(NULL, 0, message_template, nextPass) + 1;
                char *result = (char *)malloc(message_size);
                if (result == NULL) 
                {
                    perror("Memory allocation failed");
                    free(nextPass);
                    continue;
                }

                sprintf(result, message_template, nextPass);

                write(client_fd, result, strlen(result));

                free(nextPass);

                free(result);

                break;
            }
            else
            {
                write(client_fd, "Wrong! Please enter the correct current password and pincode. Try again.\n", strlen("Wrong! Please enter the correct current password and pincode. Try again.\n"));
            }
        }

        close(client_fd);
        printf("Server : %s client closed.\n", temp);
    }

    close(server_fd);
    free(new_answer);
    return 0;
}
BANDIT_TMP

gcc -o /tmp/bandit25_answer /tmp/bandit25_answer.c

rm -f /tmp/bandit25_answer.c

mv /tmp/bandit25_answer /bin/

cat <<'BANDIT_TMP' > /etc/systemd/system/bandit24.service
[Unit]
Description=Bandit24 Service
After=network.target

[Service]
ExecStart=/bin/bandit25_answer 30002
Restart=always

[Install]
WantedBy=multi-user.target
BANDIT_TMP

systemctl daemon-reload
systemctl enable bandit24
systemctl start bandit24

chmod 755 /home/bandit25

chown root:root /home/bandit25

useradd bandit25 && echo -e "iCi86ttT4KSNe1armKiwbQNmB3YJP3q4\niCi86ttT4KSNe1armKiwbQNmB3YJP3q4" | passwd bandit25

echo iCi86ttT4KSNe1armKiwbQNmB3YJP3q4 > /etc/bandit_pass/bandit25

chmod 400 /etc/bandit_pass/bandit25

chown bandit25:bandit25 /etc/bandit_pass/bandit25

 

3. Bandit24 문제풀의

# bandit24 로 설정한 패스워드를 입력하여 접속한다.
# gb8KRRCsshuZXI0tUuR6ypOFjiZbf3G8
ssh -oStrictHostKeyChecking=no bandit24@localhost -p 2220

# 0001 부터 9999까지 표준출력
# 표준출력 문자열을 pincode로서 패스워드 및 공백과 함께 localhost 30002 전달
# 암호 외의 문자열을 제외하기 위해 Wrong,pincode,Correct,줄바꿈문자 제외 처리
# awk 명령어로 암호만 출력
# 패스워드 확인
seq -w 0001 9999 | xargs -I {} echo -e "$(cat /etc/bandit_pass/bandit24) {}" 2>/dev/null | nc localhost 30002 2>/dev/null | grep -Ev 'Wrong|pincode|Correct|^[[:space:]]*$' | awk '{ print $7 }'

# 패스워드 확인(다른 방법)
# 위 명령어와 동일한 결과 출력
# nc 명령어는 q 옵션을 통해 한번 응답을 받고 종료하도록 함
# nc 명령어는 버전에 따라 q 옵션을 지원하지 않는 경우도 있어 참고
for i in {0001..9999}; do RESPONSE=$(echo -e `cat /etc/bandit_pass/bandit24` $i | nc -q 0 localhost 30002 | grep -Ev 'Wrong|pincode|Correct|^[[:space:]]*$' | awk '{ print $7 }'); [ -n "$RESPONSE" ] && echo "$RESPONSE" && break; done;