Đây là Writeup của mục General Skills. Để xem phần Writeup của các nội dung còn lại, vui lòng nhấn nút này
General Skills (Shirayama Hikari)
5.1: OpenSSH – Point: 25
Đây là bài mở đầu để hướng dẫn bạn về cơ bản của SSH

Đây là đề, từ yêu cầu của đề các bạn có thể tìm ra được cách giải sau đây: ssh vào titan.picoctf.net, cổng 65080 với username là ctf-player và mật khẩu là 6dd28e9b. Khi chạy trên Windows, chúng ta sẽ có cấu trúc dưới đây. Đương nhiên là các bạn có thể dung web shell của PicoCTF, nhưng mà chạy trên máy sẽ nhanh hơn:

ở đây, cấu trúc của dòng lệnh là: ssh <username>@<địa chỉ máy chủ> -p (để chỉ cổng chính xác kết nối) <số hiệu cổng>
Sau khi chạy, các bạn sẽ nhận được một thông báo yêu cầu chấp nhận Fingerprint. Nhấn Yes để chấp nhận, và sẽ tới màn hình này:

Nhập mật khẩu: 6dd28e9b vào và nhấn Enter
Và chúng ta đã có được flag của bài

5.2: Commitment Issues – Points: 50
Note: Trong 4 bài: Commitment Issues, Time Machine, Blame Game và Collaborative Development, chúng ta sẽ làm việc với Git, một hệ thống quản lý phiên bản phân tán (DVCS), giúp nhiều người có thể cùng làm việc trên một dự án mà không lo bị xung đột dữ liệu. Để làm được 4 bài này, các bạn cần phải cài đặt Git trên máy của mình. Nếu chưa có, các bạn truy cập vào https://git-scm.com/ và cài đặt phiên bản phù hợp cho thiết bị của mình.

Đây là đề, và từ nội dung đề có thể thấy được rằng là người ra đề đã xóa flag, và đã gửi cho mình một file .zip có tên là challenge.zip đề lấy flag.
Sau khi giải nén và mở thư mục của file .zip, chúng ta sẽ có cấu trúc như thế này:

Ở đây, chúng ta có một thư mục là .git và một file .txt là message.txt. Hãy cùng mở nó ra và xem bên trong là gì nhé.

Đúng như dự đoán, làm gì có flag trong này đâu. Nhưng mà, trong đề đã nói rằng người ra đề đã xóa flag trong file này, vậy chúng ta phải truy ngược lịch sử của file này để tìm ra flag được giấu.
Như đã đề cập ở trên, Git là một hệ thống quản lý phiên bản, nên sẽ có lưu lại lịch sử chỉnh sửa tệp. Để bắt đầu làm việc với Git, các bạn hãy mở Command Prompt / Shell tại thư mục của đề, và nhập “git init”. Lúc này, git sẽ lấy dữ liệu có sẵn từ thư mục .git để đồng bộ hóa lịch sử thay đổi.

Sau khi thiết lập git, chúng ta cần phải xem lại cái file này đã bị chỉnh sửa như thế nào rồi. Để xem lại nhật ký chỉnh sửa file, mình sử dùng lệnh git log — <filename> với filename của mình cần lấy nhật ký là message.txt. Và đây là kết quả.

Từ nhật ký này, chúng ta có thể thấy được rằng vào ngày 9/3/2024, tác giả PicoCTF ([email protected]) đã thực hiện một hành động nào đó với file với commit hash: 3d5ec8a26ee7b092a1760fea18f384c35e435139 và người này có chú thích cho hành động của mình là “create flag” là tạo flag. Để đơn giản, hãy xem commit hash này là id của mỗi hành động mà người dùng thực hiện trên file.
Như vậy lúc này chúng ta đã biết được đích đến mà file này cần được khôi phục. Và rất may mắn, git đã có sẵn lệnh để chúng ta quay ngược lịch sử. Chúng ta sẽ sử dụng lệnh git checkout <commit hash> -- <filename> với commit hash là 3d5ec8a26ee7b092a1760fea18f384c35e435139 và filename message.txt để khôi phục lại file vào thời điểm được tạo flag. Lúc này, mở lại file message.txt và chúng ta đã có được flag của bài này

5.3: Time Machine – Point: 50

Đây là đề bài, và chúng ta nhận ra ngày một điều là cần phải xem lại nhật ký chỉnh sửa tệp trên git để tìm thấy flag. Và đề chắc chắn hơn, hãy mở tệp message.txt có trong thư mục ra và xem nội dung bên trong là gì.

Đúng như dự đoán, nội dung bên trong đang gợi ý chúng ta xem lại lịch sử commit để tìm ra flag. Vậy thì hãy làm theo những gì bên trong nói thôi.
Để xem lại nhật ký chỉnh sửa file, chúng ta sử dụng lệnh git log — <filename> với filename là message.txt, và chuyện gì đang xảy ra đây?

Flag của chúng ta được giấu trong phần chú thích trong nhật ký chỉnh sửa file luôn. Thật là thú vị.
5.4: Blame Game – Point: 75

Đây là đề bài

Và đây là nội dung của file nén.
Ta có thể nhận thấy rằng từ đề bài, một lần nữa, chúng ta phải xem lại nhật ký của tệp để biết được chuyện gì đang xảy ra. Để xem lại nhật ký chỉnh sửa của tệp, ta dùng lệnh git log — <filename> với filename lúc này sẽ là message.py.
Và chúng ta đã có được flag của bài, giấu trong tên của tác giả thay vì trong phần chú thích như bài Time Machine.

5.5: Collaborative Development – Points: 75

Đây là đề

Và đây là những gì bên trong thư mục theo đề đã được giải nén
Như 3 bài trước, để biết được chuyện gì xảy ra với file này, hãy cùng xem log của nó nào. Sử dụng lệnh git log — <filename> với filename là flag.py, và, chuyện gì đây?

Log này có vẻ rất lạ, khi chỉ có một dòng như thế này, hãy cùng mở file đó lên xem nào

Trong file này cũng không có gì hết, chuyện gì đang xảy ra đây??!
Lúc này, mình bắt đầu tìm log bằng tay để xem chuyện gì đang xảy ra, và khi tới thư mục này .git\logs\refs\heads, mình thấy có một thư mục lạ, gọi là feature

Khi mở vào, mình thấy có 3 file

Mở thử file đầu tiên bằng Notepad, và đã có bất ngờ xảy ra

Đây là một nhật ký chỉnh sửa file, nhưng mà vì sao nó lại không hiển thị khi mình dùng git log vậy. Để thử mở luôn 2 file còn lại xem.

ôi vl

2 file còn lại đều là nhật ký chỉnh sửa file. Thật là thú vị. Từ đó có thể thấy rằng, việc 3 file này không nằm trong log chính là đấu hiệu cho thấy các file này có liên quan đến flag, nhưng mà đã bị giấu.
Quay trở lại tới file part-1, để biết xem bên trong mỗi part có gì thì ta sẽ sử dụng lệnh git checkout <commit hash> -- <filename>. Lúc này, mình sẽ sử dụng cái hash khác biệt nhất trong file, ở đây là 74ae5215b93a82ddf3dd37df3d4c6b5aff0a93ed cùng với tên file là flag.py để xem có chuyện gì xảy ra không.
Và đúng như mình nghi ngờ, đó chính là flag chúng ta cần tìm. Nhưng mà sao nó còn thiếu thiếu gì đó

Để sao chép nó qua một bên rồi tính tiếp.
Xong part-1 thì đến với part-2, cũng dùng lệnh git checkout, mình tìm thấy hash khác biệt nhất là b4612c914d8461d1b1a50652cc303b76813ee142. Thay vào và xem lại file, và phần thứ 2 đã hiện ra rồi.

Và ở phần cuối cùng, áp dụng tương tự cách làm trên và chúng ta đã có được phần cuối cùng của flag.

5.6 Binhexa – Points: 100

Đây là đề
Ở đây, đề đang yêu cầu mình làm việc với các phép tính cơ bản của hệ nhị phân. Và đề yêu cầu mình phải nc vào titan.picoctf.net với port là 62817. nc, hay còn gọi là netcat, là một công cụ mạng dòng lệnh được sử dụng để mở các cổng, liên kết một trình bao với một cổng, thiết lập kết nối TCP/UDP. Netcat thường có sẵn lên linux, đặc biệt là Kali Linux, nhưng ở đây mình sử dụng Windows nên mình sẽ sử dụng một phiên bản của netcat ở đây: https://eternallybored.org/misc/netcat/

Ở bài này, bạn cần thực hiện các thực hiện được yêu cầu bởi đề và ghi kết quả cuối cùng dưới dạng hex để lấy flag, ở dưới là một trường hợp mẫu:

Đây là một trong những khả năng có thể xảy ra, vì mỗi lần kết nối thì 2 số Binary Number 1 và Binary Number 2 sẽ thay đổi một cách ngẫu nhiên.
5.7: Binary Search – Points: 100

Đây là đề, ở đây, đề yêu cầu các bạn đoán con số ẩn giấu sử dụng thuật toán Binary Search: Liên tục chia đôi mảng để tìm được giá trị. Kết nối trục tiếp với máy chủ của bài, ta có được một ví dụ sau.

Đây là một ví dụ minh họa. Thực tế giá trị bạn cần tìm sẽ khác vì nó được ngẫu nhiên.
5.8: Endianness – Points: 200

Đây là đề bài. Dựa vào đây cũng có thể biết được là mình nên mong đợi những gì từ bài này. Đó là little endian và big endian.
Đây là một trong những tình huống sẽ gặp với bài này:

Ở đây, mình được cho một từ gồm 5 ký tự, và nhiệm vụ của mình là phải tìm Little Endian của nó.
Tất nhiên, việc này có thể tìm qua Google, nhưng mà mình bị Overthinking nên quyết định sẽ modify code của đề để hiện ra đáp án luôn.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>
#include <time.h>
char *find_little_endian(const char *word)
{
size_t word_len = strlen(word);
char *little_endian = (char *)malloc((2 * word_len + 1) * sizeof(char));
for (size_t i = word_len; i-- > 0;)
{
snprintf(&little_endian[(word_len - 1 - i) * 2], 3, "%02X", (unsigned char)word[i]);
}
little_endian[2 * word_len] = '\0';
return little_endian;
}
char *find_big_endian(const char *word)
{
size_t length = strlen(word);
char *big_endian = (char *)malloc((2 * length + 1) * sizeof(char));
for (size_t i = 0; i < length; i++)
{
snprintf(&big_endian[i * 2], 3, "%02X", (unsigned char)word[i]);
}
big_endian[2 * length] = '\0';
return big_endian;
}
char *generate_random_word()
{
printf("Welcome to the Endian CTF!\n");
printf("You need to find both the little endian and big endian representations of a word.\n");
printf("If you get both correct, you will receive the flag.\n");
srand(time(NULL));
int word_length = 5;
char *word = (char *)malloc((word_length + 1) * sizeof(char));
for (int i = 0; i < word_length; i++)
{
word[i] = (rand() % 26) + 'a';
}
word[word_length] = '\0';
return word;
}
int main()
{
char *challenge_word = generate_random_word();
printf("Word: %s\n", challenge_word);
fflush(stdout);
char *little_endian = find_little_endian(challenge_word);
size_t user_little_endian_size = strlen(little_endian);
char user_little_endian[user_little_endian_size + 1];
bool correct_flag = false;
while (!correct_flag)
{
printf("Enter the Little Endian representation: ");
fflush(stdout);
scanf("%10s", user_little_endian);
for (size_t i = 0; i < strlen(user_little_endian); i++)
{
user_little_endian[i] = toupper(user_little_endian[i]);
}
if (strncmp(user_little_endian, little_endian, user_little_endian_size) == 0)
{
printf("Correct Little Endian representation!\n");
fflush(stdout);
correct_flag = true;
}
else
{
printf("Incorrect Little Endian representation. Try again!\n");
fflush(stdout);
}
}
char *big_endian = find_big_endian(challenge_word);
size_t user_big_endian_size = strlen(big_endian);
char user_big_endian[user_big_endian_size + 1];
bool final_flag = false;
while (!final_flag)
{
printf("Enter the Big Endian representation: ");
fflush(stdout);
scanf("%10s", user_big_endian);
for (size_t i = 0; i < strlen(user_big_endian); i++)
{
user_big_endian[i] = toupper(user_big_endian[i]);
}
if (strncmp(user_big_endian, big_endian, user_big_endian_size) == 0)
{
printf("Correct Big Endian representation!\n");
fflush(stdout);
final_flag = true;
}
else
{
printf("Incorrect Big Endian representation. Try again!\n");
fflush(stdout);
}
}
FILE *flag = fopen("flag.txt", "r");
if (flag == NULL)
{
printf("Flag not found. Please run this on the server\n");
fflush(stdout);
exit(0);
}
char flag_content[100];
fgets(flag_content, sizeof(flag_content), flag);
printf("Congratulations! You found both endian representations correctly!\n");
fflush(stdout);
printf("Your Flag is: %s\n", flag_content);
fflush(stdout);
exit(0);
return 0;
}
Đây là đoạn mã gốc, sau khi lược bớt các hàm kiểm tra đáp án, hàm tạo từ ngẫu nhiên, và đây là kết quả
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *find_little_endian(const char *word)
{
size_t word_len = strlen(word);
char *little_endian = (char *)malloc((2 * word_len + 1) * sizeof(char));
size_t i;
for (i = word_len; i-- > 0;)
{
snprintf(&little_endian[(word_len - 1 - i) * 2], 3, "%02X", (unsigned char)word[i]);
}
little_endian[2 * word_len] = '\0';
return little_endian;
}
char *find_big_endian(const char *word)
{
size_t length = strlen(word);
char *big_endian = (char *)malloc((2 * length + 1) * sizeof(char));
size_t i;
for (i = 0; i < length; i++)
{
snprintf(&big_endian[i * 2], 3, "%02X", (unsigned char)word[i]);
}
big_endian[2 * length] = '\0';
return big_endian;
}
int main()
{
char word[256];
printf("Enter word: ");
scanf("%s", word);
char *little_endian = find_little_endian(word);
char *big_endian = find_big_endian(word);
printf("Little Endian: %s\n", little_endian);
printf("Big Endian: %s\n", big_endian);
free(little_endian);
free(big_endian);
return 0;
}
Sau khi nhập vào từ theo đề, chúng ta sẽ có kết quả sau

Sao chép và dán vào phần trả lời, và chúng ta sẽ ra được flag

↓Bonus Audio → Back to main Writeup page
Để lại một bình luận