[Pentest] WebAssembly là gì? Ưu điểm của công nghệ được tạo ra bởi Microsoft, Google, Mozilla, Apple

WebAssembly (gọi tắt là Wasm) là một công nghệ còn khá mới trong lĩnh vực phát triển ứng dụng Web, ngày càng được sử dụng phổ biến bởi ưu thế về hiệu năng cho WebApp so với ngôn ngữ lập trình Javascript, điều này mang lại những cơ hội và cũng đi kèm các thử thách mới cho Web Security trong lĩnh vực an ninh mạng.

Trong bài viết này tác giả hi vọng sẽ giúp bạn đọc, các nhà phát triển ứng dụng Web hoặc các nhà nghiên cứu trong ngành An toàn thông tin có thể tiếp cận WASM một cách nhanh nhất, thông qua một ví dụ rất đơn giản.

WebAssembly là gì? Đặc điểm của WebAssembly

Nếu như trước đây các trình duyệt Web khi tải một Website về thiết bị, chỉ cần hiểu 3 ngôn ngữ gồm HTML/CSS/Javascript là có thể tạo nên một WebApp tương tác với người dùng. Nhưng ở thời điểm hiện tại, các trình duyệt Web sẽ phải hiểu thêm một ngôn ngữ mới, đó là WebAssembly.

Đây là thành quả hợp tác giữa những tổ chức nắm giữ các trình duyệt Web phổ biến nhất hiện tại, đồng thời cũng là những gã khổng lồ trong ngành công nghệ, là Microsoft, Google, Mozilla, Apple.

  • WebAssembly sinh ra để giải quyết bài toán hiệu năng của Javascript, tận dụng sức mạnh tính toán ở phía thiết bị của người dùng, đặc biệt ở các tác vụ xử lý truyền thông đa phương tiện (video, audio, image), game, mô phỏng, thuật toán,…
  • WASM là hợp ngữ (Assembly Language) được thiết kế riêng cho các Javascript Engine, đây không hẳn là một ngôn ngữ lập trình độc lập, chỉ có các Javascript Engine mới có thể hiểu và thực thi các Instruction của WASM.
  • WASM có thể làm được mọi việc Javascript có thể làm, nhưng không phải được thiết kế để thay thế một ngôn ngữ linh động như Javascript, ít nhất ở thời điểm hiện tại vẫn cần Javascript để chạy được WASM.
  • WASM được nạp vào trình duyệt dưới định dạng nhị phân (chuỗi bytecode), vì vậy mã nguồn thường sẽ được viết bằng cách ngôn ngữ cấp cao như C/C++, Rust, … sau đó sẽ được biên dịch về định dạng nhị phân của WASM.

Ví dụ đơn giản về WebAssembly

Để hiểu thêm về công nghệ WASM, ta sẽ bắt đầu bằng một ví dụ đơn giản. Giả sử trong lập trình Javascript ta cài đặt một hàm tên add2num cho phép cộng 2 số nguyên, nhìn vào bảng bên dưới ta sẽ có được so sánh về cách biểu diễn mã nguồn:

WASM Bytecode chính là đoạn mã cuối cùng mà trình duyệt cần để thực thi. Tiếp theo đây ta sẽ cần làm một số thao tác để hàm add2num viết bằng WASM chạy được trên trình duyệt Web. Đầu tiên, tạo tập tin module.wat có nội dung như sau:

Đoạn mã này là WASM ở định dạng Text (WebAssembly Text Format, gọi tắt là WAT), sử dụng cú pháp S-Expression tương tự ngôn ngữ lập trình LISP. Các ngôn ngữ Assembly đều được thiết kế các định dạng Text đi kèm, giúp cho việc đọc và sử dụng ngôn ngữ đó được dễ dàng hơn thay vì sử dụng các Bytecode Instruction khô khan và khó nhớ.

Với đoạn mã trên, ta đã định nghĩa một hàm cộng 2 số nguyên 32-bit:

  • Các đoạn mã WASM được đóng gói trong một đối tượng gọi là module, trình duyệt sẽ dựa vào các module này để thực thi WASM.
  • Tên hàm là add2num, gồm 2 tham số $p0$p1 kiểu số nguyên 32-bit. Hàm sẽ trả về một giá trị số nguyên 32-bit thông qua lệnh chỉ thị result. Trong WASM, đặt tên biến hoặc hàm sẽ dùng dấu dollar “$” ở phía trước.
  • Khi gọi hàm sẽ có một vùng nhớ gọi là locals chứa các giá trị khởi tạo, cụ thể ở đây là 2 tham số truyền vào hàm là $p0$p1, lệnh get_local sẽ đọc các giá trị trong vùng locals này và đưa vào Stack.
  • Lệnh i32.add sẽ lấy 2 giá trị nằm trên Stack, ở đây là $p0$p1, cộng lại với nhau, kết quả trả về đưa lại vào Stack. Hàm sẽ trả về giá trị nằm trên cùng của Stack, chính là tổng của $p0$p1.
  • Lệnh export sẽ định nghĩa hàm add2num sẽ được gọi bên ngoài module thông qua nhãn wasm_add

Như đã đề cập, WASM nạp vào trình duyệt dưới dạng nhị phân, nên ta cần biên dịch nội dung của module.wat thành dạng nhị phân. Rất may, WebAssembly Binary Toolkit (gọi tắt là WABT) cung cấp rất nhiều công cụ để làm việc với WASM, trong đó có công cụ wat2wasm cho phép biên dịch các đoạn mã WAT thành bytecode.

Thực hiện lệnh sau để biên dịch module.wat

$ wat2wasm module.wat -o module.wasm

Đoạn byte-code như trên khá khó đọc, ta có thể sử dụng công cụ wasm-objdump giúp việc hiển thị byte-code bên trong tập tin WASM nhị phân module.wasm dễ đọc hiểu hơn.

$ ./wabt/bin/wasm-objdump -d module.wasm

Bạn đọc có thể tham khảo thêm ý nghĩa và cách sử dụng của các WASM Instruction tại https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md

Ở thời điểm hiện tại, bytecode của WASM sẽ được gọi từ Javascript. Tiếp tục tạo một tập tin index.html với nội dung như sau:

Đoạn Javascript trên sẽ nạp mã WASM từ tập tin module.wasm vào đối tượng wasm_instance, sau khi quá trình này diễn ra thành công, ta có thể sử dụng hàm add2num. Để kiểm tra kết quả, có thể mở một Web Server đơn giản tại thư mục đang làm việc, nhanh nhất là dùng php-cli

$ php -S 127.0.01:8888

Truy cập http://127.0.0.1:8888/index.html để xem kết quả, trong bài viết này tác giả sử dụng trình duyệt Google Chrome

Mở Chrome DevTools, kiểm tra ở Network-Tab ta sẽ thấy khi truy cập index.html, đoạn Javascript sẽ tải về tập tin module.wasm, nội dung ở định dạng nhị phân. Tiếp tục chuyển sang Console-Tab để xem mã WASM tải về có được khởi tạo thành công không.

Như ta thấy, đối tượng wasm_instance được khởi tạo thành công, đang chứa hàm wasm_add được viết bằng WASM (chính là hàm add2num được export). Có thể thử gọi hàm wasm_add ngay tại Console để kiểm tra:

Ở ví dụ trên, Javascript nạp WASM bytecode từ một tập tin riêng, bên cạnh đó ta cũng có thể truyền một chuỗi bytecode trực tiếp vào Javascript thông qua một Byte Array.

Thực hiện chuyển nội dung tập tin module.wasm sang dạng Hex Array, đơn giản nhất là sử dụng Python:

$ python -c “print [hex(ord(c)) for c in open(‘module.wasm’).read()]” | tr -d “‘“

Ta thực hiện nạp bytecode trên trực tiếp vào mã Javascript như sau:

Có thể kiểm tra nhanh đoạn mã này sử dụng DevTools Console

Ta thấy mã WASM đã chạy thành công!

Với cách tiếp cận như vậy, WASM sẽ mang lại một diện mạo mới cho WebApp, một trong những DEMO hiệu năng của WASM nổi tiếng nhất là WebAssembly Video Editor, cho phép xử lý Video thời gian thực trên trình duyệt, bạn đọc có thể tham khảo tạo địa chỉ https://github.com/shamadee/web-dsp

Kết thúc phần giới thiệu WASM, một cách cơ bản nhất có thể, hi vọng bạn đọc có thể để nắm được các khái niệm đầu tiên về công nghệ WebAssembly. Riêng đối với ngành An toàn thông tin, đây là một công nghệ khá mới với các nhà nghiên cứu mảng Web Security. Bên dưới là một số đánh giá riêng của tác giả về việc WASM sẽ có những tác động đến lĩnh vực An toàn thông tin:

  • WASM và Javascript chạy trên cùng một Sandbox của trình duyệt, về mặt cài đặt thì các JS Engine sẽ bổ sung thêm một thành phần Parser các Instruction của WASM, tạo ra một ‘Attack Surface’ mới cho tội phạm mạng để tấn công các trình duyệt.
  • Khó khăn hơn đối với các kỹ sư bảo mật trong việc phân tích các mã nguồn nhúng vào Website. Ví dụ nếu các đoạn mã đánh cắp thẻ tín dụng hoặc các đoạn mã đào tiền ảo như Coinhive ở dạng Javascript, các nhà phân tích có thể tìm ra mã độc nhanh hơn, nhưng ở dạng nhị phân như WASM, công việc sẽ khó khăn hơn rất nhiều.
  • WASM sẽ gây khó khăn cho các công cụ của bên thứ ba như tường lửa, WAF nhận diện các đoạn mã độc.
  • WASM mang lại hiệu năng cao cho WebApp, vì vậy trong tương lai sẽ xuất hiện các WebApp rất phức tạp như các chương trình soạn thảo Video, hình ảnh,… sẽ chuyển dần từ Desktop lên nền Web, tạo ra những hướng nghiên cứu mới cho bảo mật ứng dụng Web.

Ở bài viết tiếp theo, tác giả sẽ giải thích thêm về cơ chế stack-based trong WASM, đồng thời tìm hiểu cách Debug mã WASM trên các trình duyệt, áp dụng để giải quyết Challenge-5 tại sự kiện Flare On 2018 của hãng bảo mật FireEye.

Tác giả: HoangDoan — VietSunshine Pentest team

Xem thêm: [Pentest] Hướng dẫn debug code c/c++ trên Android