Phân tích phần mềm chấm thi FineLinux

FineLinux là phần mềm chấm thi môn "Linux và phần mềm mã nguồn mở" dành cho sinh viên đại học Thuỷ Lợi

Hôm nay trong buổi test thử phần mềm để chuẩn bị cho bài thi online cuối môn, tôi đã có dịp phân tích thử phần mềm này xem mức độ bảo mật của nó tới đâu, liệu có thể bị sinh viên gian lận trong quá trình thi không.

Đầu tiên sau khi tải phần mềm về và giải nén, tôi nhận được 2 file như sau:

File exe chỉ có 40kb, trông hơi khả nghi, dù sao thì tôi cũng sẽ vứt nó vào Sandboxie kèm với Fiddler proxy debugger xem liệu có capture được http request nào thú vị hay không.

Ban đầu, phần mềm hiển thị 1 form đăng nhập như sau:

Sau khi điền thông tin và bấm đăng nhập, tôi nhận được kết quả như sau (thông tin sinh viên chỉ mang tính chất tham khảo, không phải thông tin thật)

Request nhận được ở Fiddler:

Tôi nhấn thử "Xem đề trắc nghiệm", phần mềm hiển thị 1 form như sau:

Vì mục đích thử nghiệm nên tôi đánh thử vài câu rồi chọn "Chấm trắc nghiệm"

Phần mềm gửi lên 1 request như sau:

Con số 163 trông rất bí ẩn, vì vậy tôi quyết định decompile phần mềm này. Vì vừa mở lên có thể nhận thấy đấy là phần mềm viết bằng C# Winform nên tôi đã mở nó bằng phần mềm JustDecompile.

Sau một hồi tìm quanh thì tôi thấy vài điều khá thú vị

Đầu tiên là giải thích cho con số 163, đây là hàm gửi request:

Vậy con số 163 này được tạo thành bởi giá trị làm tròn của mark * heso, là 2 biến double được truyền vào hàm.

Trace theo lời gọi hàm, ta thấy hàm này được truyền vào các tham số sau:

Có vẻ heso là 1 giá trị tĩnh nào đấy, tìm phần khai báo của nó ta được kết quả sau:

heso[1] = 7

heso[2] = 3

(về sau này tôi nhận ra rằng đây là hệ số của phần trắc nghiệm và điền khuyết, trắc nghiệm chiếm 7 phần và điền khuyết chiếm 3 phần trong tổng số điểm)

Tiếp theo là biến num, nhìn lại lời gọi hàm ở trên ta thấy biến num được tính bằng hàm qf.Score. Tiếp tục trace hàm này:

Ta thấy hàm for qua các câu hỏi (0 -> answer.Length, mảng này chứa các checkbox đáp án của mỗi câu) và gọi hàm CheckAnswer2. Trace tiếp hàm này:

Chỗ này mặc dù tôi có nháp ra và đã hiểu nhưng tôi nghĩ nó hơi khó giải thích, đại loại việc nó làm là như sau:

- For qua các checkbox của câu hỏi thứ k

- Nếu checkbox thứ num1 được chọn, check xem trong đáp án có phương án này hay không, bằng cách convert số num1 ra thành chữ cái tương ứng với checkbox ("ABCDEF"[num1]) rồi  check index. Nếu có thì num += 1. Nếu không có => sv chọn sai, 0 điểm (return length = 0)

- Cuối cùng gán lại length = Số lựa chọn đúng / Tổng số đáp án đúng (num / num / (double)this.QB[k][0].Length)

- Trả về length là điểm thành phần của câu đó

Có thể đọc xong cái giải thích cái hàm CheckAnswer2 này bạn vẫn chả hiểu gì hết. Vậy thôi, với mục đích gian lận thì ta có một cách nghĩ đơn giản hơn. Cùng nhìn lại hàm Score:

double length = num * 100 / (double)((int)this.answer.Length);

- num là tổng số điểm thành phần. Trả lời đúng mỗi câu bạn sẽ được 1 điểm

- this.answer.Length là số câu hỏi

Nghĩa là tổng số điểm bài trắc nghiệm của bạn sẽ là tổng số điểm thành phần / số câu hỏi * 100 => Max là 100 điểm

Hệ số điểm của bài trắc nghiệm là 7 => Điểm gửi lên server sẽ là tổng số điểm * 7.

Quay lại với con số 163. Ta chỉ cần lấy 163 / 7 sẽ biết được số điểm tổng = 23.28 ~ 23.3 trên 100

Vậy để được max số điểm, ta chỉ cần sửa con số 163 này thành 700

Tương tự với phần điền khuyết, ta sửa params thành part2=300 để được số điểm max

Ngoài ra, ta còn có thể xem giá trị biến QB để lấy dữ liệu ngân hàng đề và đáp án, cách này đơn giản và hiệu quả, không cần phân tích nhiều: