
Intro-Rev
- Tôi tiến hành mở file bằng IDA để có thể xem code của bài này.
- Ta có thể thấy ở hàm main chính là thuật toán check flag chính của ta luôn, cùng phân tích từng phần nào.
printf("Enter flag: ");__isoc99_scanf("%s", s);if ( strlen(s) > 70 ) goto LABEL_14;- Đầu tiên, flag sẽ được nhập vào, nếu flag lớn hơn 70 ký tự thì sẽ kết thúc chương trình luôn.
v6 = 0;for ( i = 0; i < strlen(s); ++i ) { v8 = 0; v9 = 255; while ( 1 ) { v11 = (v8 + v9) / 2; if ( v11 == s[i] ) break; v4 = v6++; if ( v11 >= s[i] ) { s[v4 + 80] = 60; v9 = v11 - 1; } else { s[v4 + 80] = 62; v8 = v11 + 1; } } v3 = v6++; s[v3 + 80] = 61;}- Đây chính là hàm xử lý chính mà ta cần để ý tới.
- Mỗi ký tự trong flag sẽ được mô phỏng theo quá trình tìm kiếm nhị phân trên khoảng [0, 255].
- Các ký hiệu
<và>đại diện cho so sánh với giá trị giữa (mid).<nghĩa là mid >= ký tự, cập nhật hi = mid - 1.>nghĩa là mid < ký tự, cập nhật lo = mid + 1.
- Khi tìm thấy ký tự đúng, ký tự
=được thêm vào để đánh dấu kết thúc của chuỗi so sánh cho ký tự đó.
if ( v6 == 448 ) { for ( j = 0; (unsigned __int64)j <= 0x1BF; ++j ) { if ( s[j + 80] != target[j] ) goto LABEL_14; } puts("Correct!"); return 0;}- Sau đó đến bước kiểm tra kết quả, flag nhập vào, sau khi đi qua vòng lặp biến đổi sẽ được so sánh với mảng
targetcó sẵn của bài. - Giờ ta chỉ cần lấy dữ liệu trong mảng target và giải ngược lại thì sẽ có được flag.
- Sau đây là code python để giải flag bài này của tôi.
target = "<><<<>>=<>>=<>>><<>=<>>><><=<><<><=<><<<><=<>>>>=<<>><=<>><<<=<<>>=<>=<><>><=<<>><<<=<>>><>=<>>><<>=<>=<><><>>=<<>><=<>><=<>><=<<>><<=<>><<>=<<>><>=<>=<<>><><=<>><>>>=<>><<><=<>=<><<>><=<<>><=<>>><<>=<>><>>>=<>=<><>><=<<>><<<=<>>><>=<>>><<>=<>=<><<<>>=<>>><>=<>><>>>=<>><<><=<<>><><=<>><>>=<<>><=<>><>>>=<<>>=<<>><><=<<>><<=<>=<><><=<<>><=<>><<<=<>>><<>=<>><<=<>><><<=<>=<><<<<=<>><>><=<>><=<<>><<<=<>>><<>=<<>><<=<<>>=<>><><<=<>><>>=<<>><>=<>>>>>="target = target.split('=')
flag = []for i in target: lo, hi = 0, 255 for s in i: mid = (lo + hi) // 2 if s == '<': hi = mid - 1 elif s == '>': lo = mid + 1 ch = (lo + hi) // 2 flag.append(chr(ch))
print(''.join(flag))- Sau khi chạy code thì tôi đã có được flag cho bài này.
Flag
FortID{3a7_Y0ur_V3gg1e5_4nd_L3rn_Y0ur_Fund4m3n741_S3arch_Alg0r17hm5}First Steps
- Ở bài này chúng ta được bài cung cấp cho một file lgo nhìn cũng khá tường minh rồi nhưng tôi sẽ chuyển nó sang python để có thể nhìn quen thuộc hơn.
from PIL import Image
img = Image.open("input.png").convert("RGB")pixels = img.load()
maxx, maxy = 400, 200sol = []
def get_pixel(x, y): if 0 <= x < img.width and 0 <= y < img.height: return pixels[x, y] return (255, 255, 255)
def dfs(x, y, been): # up, right, down, left dx = [0, 1, 0, -1] dy = [1, 0, -1, 0]
dir_vec = [] been.add((x, y))
a = b = 0
for i in range(4): xx, yy = x + dx[i], y + dy[i] pix = get_pixel(xx, yy) if pix == (0, 128, 0): # green dir_vec.append(1) else: dir_vec.append(0)
if (xx, yy) not in been and pix == (0, 128, 0): a2, b2 = dfs(xx, yy, been) a += a2 b += b2
if dir_vec in ([1,1,1,0], [0,1,1,1], [1,0,1,1], [1,1,0,1]): b += 1 if dir_vec in ([1,1,0,0], [0,1,1,0], [0,0,1,1], [1,0,0,1]): a += 1
return a, b
def g(x, y): pix = get_pixel(x, y - 2) if pix == (0, 128, 0): return 3 else: return 4
def h(x, y): pix = get_pixel(x, y - 2) if pix == (0, 128, 0): return 5 else: return 6
def f(x, y): been = set() a, b = dfs(x, y, been)
ret = 10 * a + b if ret == 40: ret += g(x, y) if ret == 41: ret += h(x, y) return ret
for x in range(maxx + 1): for y in range(maxy + 1): if get_pixel(x, y) == (0, 0, 0): # black pixels[x, y] = (0, 128, 0) # convert to green sol.append(f(x, y)) pixels[x, y] = (0, 0, 0) # reset to blacktarget = [44, 47, 0, 10, 11, 43, 10, 42, 46, 21, 11, 0, 42]
if sol == target: print("Correct!")else: print("Nope!")- Rồi giờ thì ta đọc code có vẻ quen thuộc hơn nhiều rồi.
- Tiếp theo ta cùng phân tích qua code này đang làm gì.
- Đầu tiên là nó mở một tấm ảnh ra, đi qua từng pixel của ảnh.
- Nếu pixel đó là màu đen thì chuyển thành màu xanh và gọi hàm
fở ngay pixel đó. - Đầu tiên hàm
fsẽ gọi tới hàmdfs. - Hàm
dfssẽ đánh dấu pixel được gọi để tránh đi qua 2 lần, sau đó duyệt qua các pixel liền kề theo 4 hướng, nếu pixel được duyệt đó là màu xanh thì gọi dfs lại pixel đó. - Hàm
dfstrả về theo 2 biếnavàb, biếnađược cộng nếu pixel đang xét ở vị trí có 2 pixel xanh liền kề ở vị trí cạnh nhau (ngã 2 nhưng không phải đường thẳng), cònbđược cộng nếu nó ở vị trí có 3 pixel liền nhau (ngã 3). - Sau đó biến
rettrongfđược cập nhật theo công thức(10 * a) + b. - Nếu
ret == 40thì gọi hàmg, và ret sẽ có 2 trường hợp trả ra là43hoặc44. - Nếu
ret == 4thì gọi hàmh, và ret sẽ có 2 trường hợp trả ra là46hoặc47. - Ở đây chúng ta đã hoàn thành phân tích bài toán, nhưng làm sao để ta có thể giải được nó, tôi chưa thấy có dấu hiệu nào để có thể dịch ngược lại được cả.
- Thế nên tôi quyết định đọc lại đề bài xem có gọi ý gì không.
- Đề bài nói đến một kiểu vẽ theo turtle, một kiểu vẽ khá đơn giản, các nét được vẽ ra khi chú rùa di chuyển và nó chỉ là các nét thằng, tiếp theo có một thông tin tôi khai thác được là trong flag chỉ có các chữ số
Note: once you figure out the secret "digits", wrap them in FortID{} before submitting. - Dựa vào các gọi ý đó từ đề bài tôi liên tưởng đến các chữ số digital.

- Các chữ số đấy như này, nhìn vào tấm ảnh này thì ta có vẻ đã ngờ ngợ ra một điều gì đó.
- Chúng ta có thể liên tưởng các
ngã 2vàngã 3ở trong hàmdfsnhưng là các đoạn gấp của các chữ số. - Từ đó ta có thể liệu kê ra dạng mã hóa của các chữ số như sau.
1: a, b = (0, 0). ret = 02: a, b = (4, 0). ret = 40 => call g3: a, b = (2, 1). ret = 214: a, b = (1, 1). ret = 115: a, b = (4, 0). ret = 40 => call g6: a, b = (4, 1). ret = 41 => call h7: a, b = (1, 0). ret = 108: a, b = (4, 2). ret = 429: a, b = (4, 1). ret = 41 => call h- Giờ đây ta có thể khẳng định suy luận của chúng ta đã đúng nhưng vẫn còn một điều ta chưa giải ra là hàm
gvàhxử lý điểm ở pixel đó như nào. Nhưng tại chỉ có 2 x 2 = 4 trường hợp nên tôi quyết định gửi check flag 4 lần. - Sau khi ghép lại các chữ số theo thứ tự của mảng
targetvà check flag thì tôi đã có được flag cho bài này.
Flag
FortID{5917427863418}Rev From the Past
- Tôi tiến hành mở file bằng IDA để có thể đọc code của bài này.
- Vì đây là file 16-bit DOS .COM binary nên ta sẽ chỉ có thể đọc được code asm của nó.
public startproc nearclimov ax, csmov ds, axmov es, axassume es:seg000mov ss, axassume ss:seg000mov sp, 0FFFEhsticall sub_10160jb short loc_10154mov ax, word_10254mov byte_10252, almov byte_10253, ahcall sub_101E1mov al, byte_10252xor al, 0A5hmov bl, almov si, 37Ehmov di, 37Ehmov cx, 21h ; '!'- Ta sẽ men theo hàm start để có thể khai thác chương trình.
- Đầu tiên là hàm
sub_10160. - Sau khi phân tích thì tôi có thể giải thích hàm này như sau:
- Ta sẽ có flag nằm trong khoảng 80 ký tự.
- Flag sẽ được so sánh với ký tự có sẵn là
FortID{. - Sau đó đọc phần bên trong flag cho đến ký tự
}.
- Lấy
word_10254đưa vàobyte_10252vàbyte_10253. - Tiếp đến là hàm
sub_101E1.- Đầu tiên là khởi tạo một mảng từ 0-255.
word_10256là seed biến động hoán vị của mảng.- Sau đó khởi tạo một vòng lặp 0xFF (256).
- Với mỗi lần sẽ:
- Shift phải 1 bit với giá trị tương ứng trong
word_10256. - Nếu bit thấp = 1, XOR với
0xB400. - Cập nhật
word_10256tạo seed mới cho bước tiếp theo.
mov ax, word_10256xor dx, dxmov bx, cxinc bxdiv bxmov bx, dx- Tiếp đến chia seed hiện tại cho (cx + 1), remainder (dx) = vị trí hoán vị.
- bx = remainder, đây là index swap trong bảng.
- Sau đó
Swap (table[cx], table[bx]).
- Shift phải 1 bit với giá trị tương ứng trong
- Từ đó mảng 0–255 được trộn ngẫu nhiên dựa trên seed 0xB4C1.
sub_101E1thực chất là một pseudo-random permutation generator, dùng để tạo “key table” cho block flag.
- Sau đó lấy
byte_10252, XOR với 0xA5, bl được dùng làm key. - Dùng
lodsb,xor al, bl,stosblặp 0x21 (33) lần, đây là quá trình giải mã một chuỗi dài 33 byte. - Tiếp tục dùng
xlatvới một bảng, so sánh, nếu mọi thứ khớp thì in thông báo thành công. - Dưới đây tôi có viết một script python để reverse lại logic đó và giải ra flag.
def sub_101E1(seed): lst = list(range(256))
for i in range(255, 0, -1): if seed & 1: seed = (seed >> 1) ^ 0xB400 else: seed = seed >> 1 j = seed % (i + 1) lst[i], lst[j] = lst[j], lst[i] return lst
encrypted_data = [ 0x2A, 0x35, 0xA9, 0x11, 0xE3, 0x6F, 0x17, 0x79, 0x11, 0xE3, 0x79, 0x88, 0x94, 0xB2, 0x01, 0xFD, 0x68, 0x11, 0x6F, 0x01, 0xB7, 0x11, 0xAC, 0x6F, 0x53, 0x01, 0xCE, 0xE2, 0x11, 0x84, 0x35, 0x35, 0x51]
word_10254 = 0xB4C1byte_10252 = (word_10254 & 0xFF) ^ 0xA5
xor_decrypted = []for byte in encrypted_data: xor_decrypted.append(byte ^ byte_10252)
sub_table = sub_101E1(word_10254)
reverse_sub_table = [0] * 256for i in range(256): reverse_sub_table[sub_table[i]] = i
flag = ""for byte in xor_decrypted: flag += chr(reverse_sub_table[byte])
flag = "FortID{" + flag + "}"print(flag)- Sau khi chạy script thì tôi đã có được flag cho bài này.
Flag
FortID{N0w_S4v3_S3t71ng5_4nd_L4unch_D00M}Skibidi Toilet
- Đầu tiên tôi tiến hành chạy thử để xem file chall cùng với 2 file txt đi kèm để làm gì.

- File yêu cầu sử dụng theo format:
./chal input.txt. - Trước tiên tôi sử dụng đối với file
hint_input.txtvà nhận được các ký tự # nhìn qua thì khá rối.

- Tôi đã thử các cách để có thể hiểu được hint từ đề bài và khi tôi thu nhỏ màn hình terminal lại thì tôi đã thấy được các ký tự mà đề bài cung cấp.
- Và sau đó tôi tiến hành thử với file
flag_input.txtthì thấy màn hình terminal có vẻ bị đơ cứng lại không hề in ra ký tự gì cả. - Giờ thì tôi tiến hành dùng IDA để đọc code của bài này xem tại sao chúng ta lại có được các ký tự tương ứng của file
hint_input.
__int64 __fastcall main(int a1, char **a2, char **a3){ unsigned int v3; // ebx __int64 v4; // rax __int64 v5; // rax _QWORD *v6; // rax unsigned int v7; // eax __int64 v8; // rax __int64 v9; // rax int v10; // r12d _QWORD *v11; // rax _QWORD *v12; // rax unsigned int v14; // [rsp+14h] [rbp-40Ch] BYREF unsigned __int64 v15; // [rsp+18h] [rbp-408h] BYREF unsigned __int64 v16; // [rsp+20h] [rbp-400h] __int64 v17; // [rsp+28h] [rbp-3F8h] _BYTE v18[32]; // [rsp+30h] [rbp-3F0h] BYREF _BYTE v19[32]; // [rsp+50h] [rbp-3D0h] BYREF _BYTE v20[400]; // [rsp+70h] [rbp-3B0h] BYREF _BYTE v21[256]; // [rsp+200h] [rbp-220h] BYREF _QWORD v22[36]; // [rsp+300h] [rbp-120h] BYREF
v22[33] = __readfsqword(0x28u); if ( a1 == 2 ) { std::ifstream::basic_ifstream(v21, a2[1], 8LL); if ( (unsigned __int8)std::ios::operator!(v22) ) { perror("open input"); v3 = 1; } else { v6 = (_QWORD *)std::istream::operator>>(v21, &v14); if ( (unsigned __int8)std::ios::operator!((char *)v6 + *(_QWORD *)(*v6 - 24LL)) ) { std::operator<<<std::char_traits<char>>(&std::cerr, "Error: could not read brush size\n"); v3 = 1; } else if ( v14 && v14 <= 0x3C ) { v16 = (1LL << v14) - 1; std::string::basic_string(v18); std::getline<char,std::char_traits<char>,std::allocator<char>>(v21, v18); while ( 1 ) { v12 = (_QWORD *)std::getline<char,std::char_traits<char>,std::allocator<char>>(v21, v18); if ( !(unsigned __int8)std::ios::operator bool((char *)v12 + *(_QWORD *)(*v12 - 24LL)) ) break; if ( (unsigned __int8)std::string::empty(v18) ) { std::operator<<<std::char_traits<char>>(&std::cout, "\n"); } else { v7 = sub_2E42(16LL, 8LL); std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::basic_stringstream(v20, v18, v7); while ( 1 ) { v11 = (_QWORD *)std::istream::operator>>(v20, &v15); if ( !(unsigned __int8)std::ios::operator bool((char *)v11 + *(_QWORD *)(*v11 - 24LL)) ) break; if ( v16 < v15 ) { v8 = std::operator<<<std::char_traits<char>>(&std::cerr, "Error: k = "); v9 = std::ostream::operator<<(v8, v15); std::operator<<<std::char_traits<char>>(v9, " is too large\n"); v3 = 1; v10 = 0; goto LABEL_19; } v17 = sub_26DC(v15, v16); sub_288B(v19, v17, v14); std::operator<<<char>(&std::cout, v19); std::string::~string(v19); } std::operator<<<std::char_traits<char>>(&std::cout, "\n"); v10 = 1;LABEL_19: std::basic_stringstream<char,std::char_traits<char>,std::allocator<char>>::~basic_stringstream(v20); if ( v10 != 1 ) goto LABEL_22; } } v3 = 0;LABEL_22: std::string::~string(v18); } else { std::operator<<<std::char_traits<char>>(&std::cerr, "Error: brush size must be between 1 and 60\n"); v3 = 1; } } std::ifstream::~ifstream(v21); } else { v4 = std::operator<<<std::char_traits<char>>(&std::cerr, "Usage: "); v5 = std::operator<<<std::char_traits<char>>(v4, *a2); std::operator<<<std::char_traits<char>>(v5, " input.txt\n"); return 1; } return v3;}- Giờ ta cùng phân tích qua xem hàm main xem liệu nó đang làm gì.
- Trước hết chúng ta có thể thấy các thông báo được chương trình in ra như:
- “open input”.
- “Error: could not read brush size\n”.
- “Error: k = ”.
- ” is too large\n”.
- “Error: brush size must be between 1 and 60\n”.
- “Usage: ” + … + ” input.txt\n”.
- Có lẽ ta cũng không cần chú ý lắm đến các thông báo này vì ta chỉ sử dụng file mà đề bài cung cấp nên có lẽ format cũng đã chuẩn rồi.
std::ifstream::basic_ifstream(v21, a2[1], 8LL);- Đầu tiên chương trình được file input.
std::istream::operator>>(v21, &v14);- Sau đó chương trình lấy số đầu tiên trong file input và lưu vào v14.
- Điều kiện thoải mãn của v14 ở đây là
v14 && v14 <= 0x3C(1 <= v14 <= 60).
v16 = (1LL << v14) - 1;- Sau đó tọa một mask bit gồm v14 bit 1 (v14: 4 => v16: 10000 - 1 = 1111).
std::getline<char,std::char_traits<char>,std::allocator<char>>(v21, v18);- Sau đó đọc từng dòng trong file ra v18.
- Chuyển v18 (chuỗi dòng hiện tại) thành stringstream v20.
std::istream::operator>>(v20, &v15);- Tiếp đến là lặp qua từng số trong v20 và gán vào v15.
v17 = sub_5555555566DC(v15, v16);sub_55555555688B(v19, v17, v14);std::operator<<<char>(&std::cout, v19);std::string::~string(v19);- Tiếp theo dữ liệu được đi qua 2 hàm
sub_5555555566DCvàsub_55555555688Bđể xử lý và rồi gán lại vào v19 để in ra. - Vậy ở đây 2 hàm
sub_5555555566DCvàsub_55555555688Bxử lý dữ liệu như nào. - Tôi tiến hành debug thử và có thể kết luận lại như sau:
- hàm
sub_5555555566DCxử lý các số nhập vào qua một thuật toán nào đó để có thể biến đổi lại số đó thành 1 số khác, các số này trong giới hạn(0, pow(2, v14) - 1). - hàm
sub_55555555688Bchuyển đổi lại số vừa đc biến đổi thành các ký tự#theo binary theo độ dàiv14. (VD: có v14 = 8 và v17 = 10 -> 00001010, số 0 sẽ được thay thành một ký tự\x20, còn 1 thì được thay thành ký tự#).
- hàm
- Từ đó mà chương trình có thể vẽ ra được các ký tự giống như lúc đầu ta thấy.
- Vì 2 hàm này được bị lồng rất nhiều hàm ở bên trong để làm rối code nên dưới đây tôi có một đoạn script python mà tôi dựng lại cách xử lý của hàm
sub_5555555566DCvàsub_55555555688Bđối với dữ liệu của filehint_input.txt.
def sub_555555556589(container_a1, container_a2, max_range): if not container_a2: return 1 best_value = 0 max_min_distance = 0
for candidate in range(1, max_range + 1): if candidate in container_a1: continue
min_distance = float('inf') for existing in container_a2: distance = abs(candidate - existing) min_distance = min(min_distance, distance)
if min_distance > max_min_distance: max_min_distance = min_distance best_value = candidate return best_value if best_value > 0 else 1
def sub_5555555566DC(argc, brush_size): if argc <= 1: return argc
mask = (1 << brush_size) - 1 if argc == 2: return mask
container_v9 = set([1, mask]) container_v8 = set([1, mask])
v6 = 0 for _ in range(3, argc + 1): v6 = sub_555555556589(container_v9, container_v8, mask) container_v9.add(v6) container_v8.add(v6) return v6
def sub_55555555688B(val, brush_size): for row in val: for pattern in row: print(''.join('#' if (pattern >> (brush_size - 1 - i)) & 1 else ' ' for i in range(brush_size)), end='') print()
brush_size = 8hint_input = [ [6, 179, 247, 34, 2, 224, 159, 31, 254, 6, 6, 2, 17, 254, 112, 9, 126, 2, 131, 120, 2, 65, 2, 20, 10, 254, 96, 240, 14, 254, 2, 14, 252, 127, 112, 33, 240, 191, 246, 34, 2, 112, 255, 143, 220, 10, 12, 191, 227, 66, 6], [6, 176, 17, 34, 34, 0, 129, 66, 66, 10, 224, 224, 230, 0, 112, 204, 1, 192, 198, 152, 3, 129, 0, 40, 152, 195, 18, 248, 230, 0, 224, 34, 34, 152, 120, 198, 10, 66, 34, 34, 224, 1, 65, 66, 40, 10, 236, 6, 177, 34, 6], [6, 176, 99, 198, 34, 0, 129, 66, 66, 140, 3, 224, 230, 0, 112, 204, 1, 192, 204, 1, 3, 129, 0, 78, 153, 0, 18, 236, 230, 0, 224, 34, 34, 152, 108, 204, 0, 66, 34, 34, 224, 1, 65, 66, 78, 152, 198, 6, 176, 204, 6], [191, 120, 198, 230, 34, 18, 129, 131, 254, 135, 0, 2, 17, 252, 112, 9, 124, 2, 135, 124, 2, 129, 255, 153, 153, 80, 18, 230, 14, 252, 2, 17, 252, 152, 102, 102, 248, 66, 135, 254, 2, 192, 255, 66, 153, 153, 255, 191, 224, 248, 6], [6, 176, 198, 46, 34, 0, 129, 66, 18, 66, 0, 56, 34, 0, 177, 18, 1, 195, 0, 140, 3, 129, 0, 152, 54, 66, 18, 227, 230, 0, 224, 34, 10, 152, 99, 204, 10, 66, 34, 34, 224, 1, 192, 195, 152, 54, 66, 176, 3, 6, 6], [6, 176, 198, 40, 34, 0, 129, 66, 34, 66, 0, 112, 198, 0, 78, 18, 1, 65, 34, 152, 3, 129, 0, 10, 124, 199, 18, 56, 230, 0, 224, 34, 18, 152, 33, 198, 12, 66, 34, 34, 224, 1, 192, 195, 10, 62, 66, 6, 224, 6], [6, 179, 246, 36, 34, 18, 129, 66, 66, 66, 0, 224, 14, 254, 36, 143, 126, 192, 33, 120, 2, 65, 2, 10, 12, 253, 96, 112, 14, 254, 2, 230, 34, 127, 65, 33, 232, 66, 34, 34, 2, 112, 2, 143, 216, 185, 66, 6, 6, 6, 6],]
results_data = []for line in hint_input: results_data.append(sub_5555555566DC(num, brush_size) for num in line)sub_55555555688B(results_data, brush_size)- Rồi giờ thì code đã khá tường minh rồi và tôi đã test thì kết quả được in ra là như mong đợi.
- Nhưng vấn đề ở đây là brush_size của file hint chỉ là 8 còn với file flag là tận 60 nên với thuật toán này thì ta không thể giải quyết việc in ra flag được thì vấn đề thời gian là rất rất lớn.
- Vì thế ở đây ta cần một thuật toán nào đó tối ưu hơn để có thể giải được bài này.
- Tuy ở đây tôi cũng chưa tìm được thuật toán nào có thể giải chính xác các con số lớn nhưng tôi đã có cho mình 2 script khá tối ưu và giải ra được một đoạn flag đã đẹp.
# Script flag 1
def solve_main(argc, brush_size): if argc <= 1: return argc
mask = (1 << brush_size) - 1 if argc == 2: return mask
j = argc - 2 m = j.bit_length() t = j - (1 << (m - 1))
if m <= brush_size: val = (2 * t + 1) << (brush_size - m) else: val = (2 * t + 1) >> (m - brush_size) return val & mask
def sub_55555555688B(val, brush_size): for row in val: for pattern in row: print(''.join('#' if (pattern >> (brush_size - 1 - i)) & 1 else ' ' for i in range(brush_size)), end='') print()
brush_size = 60flag_input = [ [54025603343196096, 640065713366106880, 54043196064792684, 1154610357701165056, 36030962187370528, 1139094314385440, 291621270414426594, 68721542130, 864154695629799487, 1152929776726958080, 2100], [99079191803726946, 685405175251730432, 864691128857788620, 48481590937114, 72064295901331554, 2278188498747490, 291621272025039714, 68722673178, 24826704522379266, 96758737667682, 4194], [198175853282990274, 686236408861418303, 919156536853382848, 202644391259749570, 72070791653688834, 1294784894546477440, 291622223905523298, 144128382268996672, 18120790167715842, 808283879726134271, 1166643409721491456], [216058654098462914, 685669064082207584, 114894567106809048, 1154610354971325190, 576530875590127864, 871446531168149248, 291622232493444194, 288247901705342146, 583243010728263743, 1168714228417422092, 5730], [198184990929852610, 612493120638818736, 919156536854472384, 198580596119948482, 576461197261168652, 871446534389367168, 291622095054491642, 2251800619831290, 18437451928403970, 73750621854369378, 22916], [99092495464926306, 685405181291803489, 919719486807893708, 198580596119804100, 576514367211094796, 880453733644132736, 289946439333757026, 288243782999474370, 18437442466054146, 73748200029783650, 5634], [49543962809573312, 685101713289110334, 56253211778088044, 1153994610977260022, 1296508385424015864, 20099064067266812, 1263226164613316803, 216106744813845568, 18440944340803578, 73747478433299554, 5730], [0, 10, 2050, 0, 0, 0, 0, 0, 0, 0, 4098], [0, 36, 1088, 0, 0, 0, 0, 0, 0, 0, 2052],]
results_data = []for line in flag_input: results_data.append(solve_main(num, brush_size) for num in line)sub_55555555688B(results_data, brush_size)# Script flag 2
def kth_point(n, left, right): if n == 1: return left if n == 2: return right
mid = (left + right) // 2 if n == 3: return mid
path = bin(n)[3:] node_left, node_right = left, right node_mid = mid
for c in path: if c == '0': node_right = node_mid else: node_left = node_mid node_mid = (node_left + node_right) // 2 return node_mid
def solve_main(argc, brush_size): mask = (1 << brush_size) - 1 return kth_point(argc, 1, mask)
def sub_55555555688B(val, brush_size): for row in val: for pattern in row: print(''.join('#' if (pattern >> (brush_size - 1 - i)) & 1 else ' ' for i in range(brush_size)), end='') print()
brush_size = 60flag_input = [ [54025603343196096, 640065713366106880, 54043196064792684, 1154610357701165056, 36030962187370528, 1139094314385440, 291621270414426594, 68721542130, 864154695629799487, 1152929776726958080, 2100], [99079191803726946, 685405175251730432, 864691128857788620, 48481590937114, 72064295901331554, 2278188498747490, 291621272025039714, 68722673178, 24826704522379266, 96758737667682, 4194], [198175853282990274, 686236408861418303, 919156536853382848, 202644391259749570, 72070791653688834, 1294784894546477440, 291622223905523298, 144128382268996672, 18120790167715842, 808283879726134271, 1166643409721491456], [216058654098462914, 685669064082207584, 114894567106809048, 1154610354971325190, 576530875590127864, 871446531168149248, 291622232493444194, 288247901705342146, 583243010728263743, 1168714228417422092, 5730], [198184990929852610, 612493120638818736, 919156536854472384, 198580596119948482, 576461197261168652, 871446534389367168, 291622095054491642, 2251800619831290, 18437451928403970, 73750621854369378, 22916], [99092495464926306, 685405181291803489, 919719486807893708, 198580596119804100, 576514367211094796, 880453733644132736, 289946439333757026, 288243782999474370, 18437442466054146, 73748200029783650, 5634], [49543962809573312, 685101713289110334, 56253211778088044, 1153994610977260022, 1296508385424015864, 20099064067266812, 1263226164613316803, 216106744813845568, 18440944340803578, 73747478433299554, 5730], [0, 10, 2050, 0, 0, 0, 0, 0, 0, 0, 4098], [0, 36, 1088, 0, 0, 0, 0, 0, 0, 0, 2052],]
results_data = []for line in flag_input: results_data.append(solve_main(num, brush_size) for num in line)sub_55555555688B(results_data, brush_size)- Sử dụng cùng lúc 2 script để in ra các flag “gần đúng” và thêm một chút phán đoán thì tôi đã có được flag cho bài này.
Flag
FortID{Sk1bidy_Toil3t_Y0u_S0lv3d_7h3_Ur1n4l_S3lec710n_Pr0bl3m!}