--- --- -Đầu tiên, mình cảm ơn BTC đã cho sinh viên trường ngoài như mình tham gia và xin góp vui WU vài bài mà mình đã giải được trong wargame lần này của HUST --- CHECK KEY --- ![image](https://hackmd.io/_uploads/BJ0dvirDZl.png) -Đề bài cho mình một file thực thi `.exe`, tải về và check thử xem thôi ![image](https://hackmd.io/_uploads/Hk8JuiSwZl.png) - Sơ qua về file, mình thấy được đây là file `ELF64`, được viết bằng ngôn ngữ `C`, không có vấn đề gì về việc bị `packed` -Oke giờ mình sẽ mở IDA lên để xem bên trong nhé -Check hàm main ```cl= int __fastcall main(int argc, const char **argv, const char **envp) { char v3; // bl __int64 v4; // rax char v5; // bl unsigned __int64 j_1; // rbx unsigned __int64 i_1; // rbx char *v8; // rax bool v9; // bl char *v10; // rax char *v11; // rax unsigned __int64 k_1; // rbx bool v13; // bl _BYTE v15[32]; // [rsp+0h] [rbp-120h] BYREF _BYTE v16[32]; // [rsp+20h] [rbp-100h] BYREF _BYTE v17[47]; // [rsp+40h] [rbp-E0h] BYREF char v18; // [rsp+6Fh] [rbp-B1h] BYREF _BYTE v19[32]; // [rsp+70h] [rbp-B0h] BYREF _BYTE v20[32]; // [rsp+90h] [rbp-90h] BYREF _BYTE v21[32]; // [rsp+B0h] [rbp-70h] BYREF _BYTE v22[40]; // [rsp+D0h] [rbp-50h] BYREF char *v23; // [rsp+F8h] [rbp-28h] int k; // [rsp+104h] [rbp-1Ch] int j; // [rsp+108h] [rbp-18h] int i; // [rsp+10Ch] [rbp-14h] v23 = &v18; std::string::basic_string<std::allocator<char>>(v17, "BKSEC{CHAO_MUN9_D3N_R3V3RS3!!!}`", &v18); std::__new_allocator<char>::~__new_allocator(&v18); std::string::basic_string(v16); std::string::basic_string(v15); std::operator<<<std::char_traits<char>>(&_bss_start, "Enter password: "); std::operator>><char>(&std::cin, v15); if ( std::string::length(v15) == 28 ) { for ( i = 0; ; ++i ) { i_1 = i; if ( i_1 >= std::string::length(v15) ) break; for ( j = 0; ; ++j ) { j_1 = j; if ( j_1 >= std::string::length(v17) ) break; v3 = *(_BYTE *)std::string::operator[](v15, i); v4 = std::string::length(v17); v5 = *(_BYTE *)std::string::operator[](v17, v4 - j - 1) ^ v3; *(_BYTE *)std::string::operator[](v15, i) = v5; } } for ( k = 0; ; ++k ) { k_1 = k; if ( k_1 >= std::string::length(v15) ) break; v8 = (char *)std::string::operator[](v15, k); CanYouCatchMe[abi:cxx11](v19, (unsigned int)*v8); v9 = std::string::length(v19) == 1; std::string::~string(v19); if ( v9 ) { std::string::operator+=(v16, "0"); v10 = (char *)std::string::operator[](v15, k); CanYouCatchMe[abi:cxx11](v20, (unsigned int)*v10); std::string::operator+=(v16, v20); std::string::~string(v20); } else { v11 = (char *)std::string::operator[](v15, k); CanYouCatchMe[abi:cxx11](v21, (unsigned int)*v11); std::string::operator+=(v16, v21); std::string::~string(v21); } } std::string::basic_string(v22, v16); v13 = CheckKey((__int64)v22); std::string::~string(v22); if ( v13 ) std::operator<<<std::char_traits<char>>(&_bss_start, "You are handsome"); else std::operator<<<std::char_traits<char>>(&_bss_start, "Try again to be handsome"); } std::string::~string(v15); std::string::~string(v16); std::string::~string(v17); return 0; } ``` - Nhìn sơ qua ta thấy rằng cần điều kiện là nhập một `password` và kiểm tra thông qua độ dài `28` và hàm `CheckKey`: + Nếu đúng trả về `"You are handsome"` + Nếu sai trả về `"Try again to be handsome"` -Hàm CheckKey ```c= _BOOL8 __fastcall CheckKey(__int64 a1) { return (unsigned __int8)std::operator==<char>(a1, "636A7264625A76126D62116C127E75117E731277127372120000005C") != 0; } ``` -- Hàm mình cần chú ý: ```c= if ( std::string::length(v15) == 28 ) { for ( i = 0; ; ++i ) { i_1 = i; if ( i_1 >= std::string::length(v15) )//len=28 break; for ( j = 0; ; ++j ) { j_1 = j; if ( j_1 >= std::string::length(v17) )//len=33 break; v3 = *(_BYTE *)std::string::operator[](v15, i); v4 = std::string::length(v17); v5 = *(_BYTE *)std::string::operator[](v17, v4 - j - 1) ^ v3; *(_BYTE *)std::string::operator[](v15, i) = v5; } } ``` Vì khá khó hiểu nên mình sẽ viết lại như sau: ```c= // input: chuỗi nhập vào (len = 28) // key: chuỗi v17 (len = 33) for (int i = 0; i<28; i++) { for (int j = 0; j<key.size(); j++) { pw[i] ^= key[key.size() - j - 1]; } } ``` Sau khi gọn lại code, mình thấy rằng password đã bị XOR với key để thành chuỗi hex `636A7264625A76126D62116C127E75117E731277127372120000005C` nên bây giờ chỉ việc làm ngược lại thôi là ra flag Code reversed của mình: ```c= #include <bits/stdc++.h> using namespace std; int main() { string key = "BKSEC{CHAO_MUN9_D3N_R3V3RS3!!!}`"; int pw[] = { 0x63,0x6A,0x72,0x64,0x62,0x5A,0x76,0x12, 0x6D,0x62,0x11,0x6C,0x12,0x7E,0x75,0x11, 0x7E,0x73,0x12,0x77,0x12,0x73,0x72,0x12, 0x00,0x00,0x00,0x5C }; for (int i = 0; i<28; i++) { for (int j = 0; j<key.size(); j++) { pw[i] ^= key[key.size() - j - 1]; } } for (int i = 0; i<28; i++) cout<<char(pw[i]); } ``` FLAG: BKSEC{W3LC0M3_T0_R3V3RS3!!!} p/s: Bài này hơi sú vì lúc đầu mình nhập thử cái key mà vẫn correct bài này trên web, sau đó mới hỏi author và sửa lại cho đúng... ![image (1)](https://hackmd.io/_uploads/H1aJ4aSwWl.png) --- JAV-REV --- Đề bài khá sú :v ![image](https://hackmd.io/_uploads/HyeWIzaBD-e.png) - Bài này có 2 files nhưng chỉ cần download file `chall.java` là đủ solve rùi - Source code: ```java= import java.util.Scanner; class Spid3rRev { public static String fourth(String t) { return t.substring(19) + t.substring(0, 19); } public static String third(String t) { String s = ""; for (int i = 0; i < t.length(); i++) { if (i % 3 == 0) s += (char)(t.charAt(i) + (i / 3)); else if (i % 3 == 2) s += (char)(t.charAt(i) + ((i - 2) / 3)); else s += t.charAt(i); } return s; } public static String second(String t) { String a = t.substring(0, 2); String b = t.substring(2, t.length() - 16); String c = t.substring(t.length() - 16); return c + b + a; } public static String first(String t) { int[] adj = { -11, 34, -28, -8, -57, -8, 2, 3, 5, -17, -13, -18, -53, -5, 0, 3, -19, -16, -12, -6, -48, 10, 7, -19, -4, -1, -67, -19, -15, 9, -47, -14, -8, -27, 3, -19, 3, -59, 5, -30, 8, 33, 22, -6, -50, 0 }; String s = ""; for (int i = 0; i < t.length(); i++) s += (char)(t.charAt(i) + adj[i]); return s; } public static void main(String[] args) { Scanner in = new Scanner(System.in); String flag = in.nextLine(); String match = "Deim(yobzoRoA`m\u0089`ESf;xmOkh ]g}8VjFw[x-tG\u008dlaVCr"; if (flag.length() == 46 && first(second(third(fourth(flag)))).equals(match)) System.out.println("Congratulations!!!!!!!!, Access Granted"); else System.out.println("Access Denied! Please try again!"); in.close(); } } ``` -Vẫn như bài trước thui, bài này check `input` với độ dài 46 và qua `4` điều kiện có `flag` hoàn chỉnh - Flow của bài này được xử lí tuần tự như sau: - Xử lí 4-->Xử lí 3-->Xử lí 2-->Xử lí 1 --> Việc của mình là làm ngược lại thôi (1-->2-->3-->4) -Code của mình để reverse bài này ```c= #include <bits/stdc++.h> #define ll long long using namespace std; string inv_fourth(const string &t) { //original: ABCDEFGHIJKLMNOPQRSTUVWXYZ //encoded: TUVWXYZABCDEFGHIJKLMNOPQRS(bị dịch trái từ kí tự 19 ) return t.substr(t.size() - 19) + t.substr(0, t.size() - 19); } string inv_third(const string &t) { string s = ""; for (int i = 0; i < (int)t.size(); i++) { if (i % 3 == 0) s += char(t[i] - (i / 3)); else if (i % 3 == 2) s += char(t[i] - ((i - 2) / 3)); else s += t[i]; } return s; } string inv_second(const string &t) { // t = c + b + a //original = "ABxxxxxxxxxxxxxxxxYYYYYYYYYYYYYYYY" //encoded=YYYYYYYYYYYYYYYYxxxxxxxxxxxxxxxxAB string a = t.substr(t.size() - 2); // 2 ký tự cuối string b = t.substr(16, t.size() - 18); // phần giữa string c = t.substr(0, 16); // 16 ký tự đầu return a + b + c; } string inv_first(const string &t) { int adj[] = { -11, 34, -28, -8, -57, -8, 2, 3, 5, -17, -13, -18, -53, -5, 0, 3, -19, -16, -12, -6, -48, 10, 7, -19, -4, -1, -67, -19, -15, 9, -47, -14, -8, -27, 3, -19, 3, -59, 5, -30, 8, 33, 22, -6, -50, 0 }; string s = ""; for (int i = 0; i < (int)t.size(); i++) s += char(t[i] - adj[i]); return s; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string match = "Deim(yobzoRoA`m\x89`ESf;xmOkh ]g}8VjFw[x-tG\x8dlaVCr"; string s1 = inv_first(match); string s2 = inv_second(s1); string s3 = inv_third(s2); string flag = inv_fourth(s3); cout<<flag; } } ``` Flag: BKSEC{java_is_the_wursT_kind_of_prog_language} --- JSLOCK1 --- ![image](https://hackmd.io/_uploads/SkPcO0HDbl.png) Đề bài cho mình một trang web,click vào thử thôi ![image](https://hackmd.io/_uploads/HJYAOCHv-l.png) -Ok, đề bài kêu mình nhập mật khẩu có 5 chữ số, và điều đầu tiên khi mình làm những bài `wasm` như này là mình sẽ tra bằng inspect để kiếm file `main` ![image](https://hackmd.io/_uploads/BJSVtArvWx.png) Sau khi inspect, mình thấy được 3 files nhưng sau khi vào từng file thì mình chỉ thấy cần chú ý đến `lock.js` ``` // Check password here const correctPassword = [20, 14, 16, 13, 18]; function checkPassword() { const dials = document.querySelectorAll('.dial'); const enteredPassword = Array.from(dials).map(dial => Number(dial.value)); const decodedPassword = [ enteredPassword[0] + enteredPassword[1] + enteredPassword[2], enteredPassword[1] + enteredPassword[2] + enteredPassword[3], enteredPassword[2] + enteredPassword[3] + enteredPassword[4], enteredPassword[3] + enteredPassword[4] + enteredPassword[0], enteredPassword[4] + enteredPassword[0] + enteredPassword[1], ]; if (JSON.stringify(decodedPassword) === JSON.stringify(correctPassword)) { const passwordString = enteredPassword.join(''); const hexPassword = new TextEncoder().encode(passwordString).reduce((prev, curr) => prev + curr.toString(16).padStart(2, '0'), ''); const base64Password = btoa(hexPassword); alert("Mở khóa thà nh công! Cờ cá»§a bạn là BKSEC{" + base64Password + "}"); } else { alert('Mật khẩu không chính xác. Vui lòng thá»­ lại.'); } } ``` Nhìn vào code giải mã thì không quá là rối, hàm `checkPassword` tạo một hệ phương trình tuyến tính 5 ẩn để tạo ra 5 số là password của đề bài, bài toán như sau: --> a+b+c=20 b+c+d=14 c+d+e=16 d+e+a=13 e+a+b=18 Để giải được phương trình này, mình sẽ sử dụng một hàm rất phổ biến trong toán học, đó là `z3` của python Nếu các bạn chưa bieest`z3` là gì, có thể tham khảo link sau: https://anishkumarroy.github.io/posts/z3-in-reversing/ ```python= from z3 import * a,b,c,d,e= Ints('a b c d e') s=Solver() s.add( a+b+c==20, b+c+d==14, c+d+e==16, d+e+a==13, e+a+b==18 ) if s.check()==sat: m=s.model() print("a=",m[a]) print("b=",m[b]) print("c=",m[c]) print("d=",m[d]) print("e=",m[e]) else: print("No solution") ``` Sau khi nhập xong 5 chữ số, flag sẽ xuất hiện ![image](https://hackmd.io/_uploads/ByKxhRHvZg.png) Flag:BKSEC{MzYzNTM5MzAzNw==} P/s2: Chall này rất hay nma xui thay lại bị lỗi luôn lúc submit flag, may mắn là mình vẫn báo kịp cho author biết để sửa --- JSLOCK2 --- ![image](https://hackmd.io/_uploads/Bk-qhABv-e.png) - Bài này là bản nâng cấp của JSLOCK1 nên lúc đầu mình cũng chuẩn bị tâm lí là đề cho một đống phương trình toán rùi =)) ![image](https://hackmd.io/_uploads/SkDgT0Svbx.png) Và quả nhiên là vậy, vẫn là crack `password` nhưng lần này lên đến 12 số =))), nhưng không sao, nếu mà mấy bạn đã quen sử dụng z3 thì chall này sẽ "mềm" đi rất nhiều -Vẫn xài cách cũ và mình lấy được hàm crackpass như sau: ```// Check password here const correctPassword = [-4, 11, 8, 10, 31, 0, 28, 4, 1, 25, 10, 11]; function checkPassword() { const dials = document.querySelectorAll('.dial'); const enteredPassword = Array.from(dials).map(dial => Number(dial.value)); const decodedPassword = [ enteredPassword[0] * enteredPassword[1] - 2 * enteredPassword[2], enteredPassword[1] + 5 * enteredPassword[2] - 3 * enteredPassword[3], enteredPassword[2] + enteredPassword[3] * enteredPassword[4] - enteredPassword[0], enteredPassword[5] + 2 * enteredPassword[4] + enteredPassword[2], 20 * enteredPassword[1] - 2 * enteredPassword[2] - enteredPassword[4], enteredPassword[2] + enteredPassword[5] - 2 * enteredPassword[1], 2 * enteredPassword[1] + enteredPassword[2] + 3 * enteredPassword[6] + 4 * enteredPassword[7], 5 * enteredPassword[5] - enteredPassword[7] - enteredPassword[8] + 2 * enteredPassword[9], 3 * enteredPassword[8] + 2 * enteredPassword[9] + 4 * enteredPassword[10] - 3 * enteredPassword[6], 9 * enteredPassword[11] + 2 * enteredPassword[10] - enteredPassword[8], 4 * enteredPassword[7] - enteredPassword[8] + enteredPassword[10], enteredPassword[3] ** enteredPassword[8] + 3 * enteredPassword[11] - 2 * enteredPassword[7] + enteredPassword[6] + enteredPassword[5] + enteredPassword[10], ]; if (JSON.stringify(decodedPassword) === JSON.stringify(correctPassword)) { const passwordString = enteredPassword.join(''); const hexPassword = new TextEncoder().encode(passwordString).reduce((prev, curr) => prev + curr.toString(16).padStart(2, '0'), ''); const base64Password = btoa(hexPassword); alert("Mở khóa thà nh công! Cờ cá»§a bạn là BKSEC{" + base64Password + "}"); } else { alert('Mật khẩu không chính xác. Vui lòng thá»­ lại.'); } } ``` - Nhìn mà nhức nhức cái đầu á =))), nhưng chall này sẽ tiếp tục xài z3 để solve tiếp nhé ```python= from z3 import * a, b, c, d, e, f, g, h, i, j, k, l = Ints('a b c d e f g h i j k l') s = Solver() # giới hạn miền (rất quan trọng vì có lũy thừa) for x in [a,b,c,d,e,f,g,h,i,j,k,l]: s.add(x >= 0, x <= 9) s.add( a*b - 2*c == -4, b + 5*c - 3*d == 11, c + d*e - a == 8 f + 2*e + c == 10, 20*b - 2*c - e == 31, c + f - 2*b == 0, 2*b + c + 3*g + 4*h == 28, 5*f - h - i + 2*j == 4, 3*i + 2*j + 4*k - 3*g == 1, 9*l + 2*k - i == 25, 4*h - i + k == 10, d**i + 3*l - 2*h + g + f + k == 11 ) if s.check() == sat: m = s.model() print("a =", m[a]) print("b =", m[b]) print("c =", m[c]) print("d =", m[d]) print("e =", m[e]) print("f =", m[f]) print("g =", m[g]) print("h =", m[h]) print("i =", m[i]) print("j =", m[j]) print("k =", m[k]) print("l =", m[l]) else: print("No solution") ``` ![image](https://hackmd.io/_uploads/BJbIk1Iv-l.png) FLAG: BKSEC{MzEzMjMzMzIzMzMxMzMzMzMyMzIzMDMz} - Các bạn có thể tham khảo thử 1 chall của web CHH cũng xài `z3` để solve: https://battle.cookiearena.org/challenges/reverse-engineering/zi-zay-3