Featured Post

Có một Biển Đông trên không gian mạng

Có một Biển Đông trên không gian mạng Thái Dương Mùa hè 2014, giữa lúc người Việt trong nước và hải ngoại đang sôi sục vì Trung Quốc đư...

Wednesday, March 30, 2016

Một nghiên cứu thất bại

Người tìm lổ hổng phần mềm chuyên nghiệp như tôi ít ai nói về các nghiên cứu thất bại. Tôi cũng chưa từng nói, mặc dù thất bại nhiều lắm, không phải vì xấu hổ, chỉ vì lười, kể một câu chuyện dài mà rốt cuộc chẳng có kết cục đẹp thì kể làm gì. Nhưng vừa rồi tôi mới làm một nghiên cứu, thất bại ê chề, tốn tiền tốn của mà chẳng thu được gì, nên tôi muốn gỡ vốn bằng cách viết lại, để mai mốt bạn nào có làm biết đường mà tránh.

Không dông dài nữa, câu chuyện là thế này. Có người nhờ tôi coi đoạn chương trình Java này: https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/tls/OkHostnameVerifier.java. Đoạn code này có nhiệm vụ rất quan trọng: kiểm tra tên miền của các certificate (chứng chỉ) SSL. Chứng chỉ SSL giống như passport, trên đó có tên miền của máy chủ, kèm theo chữ ký điện tử của một cơ quan có thẩm quyền, được gọi là Certificate Authority. Khi kết nối đến một máy chủ nào đó, để đảm bảo an toàn bạn phải kiểm tra xem tên miền trên chứng chỉ của máy chủ có trùng với tên miền mà bạn đang muốn kết nối hay không. Đây chính là chức năng của đoạn code ở trên.

Tôi tìm thấy một vấn đề ở hàm verifyHostname ở dòng thứ 73:

  /** Returns true if {@code certificate} matches {@code hostname}. */
  private boolean verifyHostname(String hostname, X509Certificate certificate) {
    hostname = hostname.toLowerCase(Locale.US);
    boolean hasDns = false;
    List<String> altNames = getSubjectAltNames(certificate, ALT_DNS_NAME);
    for (int i = 0, size = altNames.size(); i < size; i++) {
      hasDns = true;
      if (verifyHostname(hostname, altNames.get(i))) {
        return true;
      }
    }

    if (!hasDns) {
      X500Principal principal = certificate.getSubjectX500Principal();
      // RFC 2818 advises using the most specific name for matching.
      String cn = new DistinguishedNameParser(principal).findMostSpecific("cn");
      if (cn != null) {
        return verifyHostname(hostname, cn);
      }
    }

    return false;
  }

Hàm này nhận vào một certificate và tên miền, trả về true nếu tên miền trùng với một trong những tên miền của chứng chỉ; ngược lại trả về false. Quá trình kiểm tra gồm hai giai đoạn:

1/ Kiểm tra xem tên miền nhập vào có trùng với tên miền nào trong mục SubjectAltName của chứng chỉ. Nếu có trả về true; nếu không thực hiện bước 2.

2/ Kiểm tra xem tên miền nhập vào có trùng với phần Common Name trong mục Distinguished Name của chứng chỉ. Nếu có trả về true; nếu không trả về false.

Tôi chú ý đến phần so sánh Common Name và mở code của DistinguishedNameParser ra đọc: https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/internal/tls/DistinguishedNameParser.java.

Distinguished Name có thể có giá trị như sau:

C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com

DistinguishedNameParser khá phức tạp, nhưng tóm tắt thì nhiệm vụ của hàm findMostSpecific là đi tìm chuỗi CN= trong mục Distinguished Name và trả về www.google.com. Lúc coi đến đây, tôi tự hỏi: chuyện gì xảy ra nếu trong Distinguished Name có đến hai Common Name? Ví dụ như:

C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com, CN=www.evil.com

Lúc này DistinguishedNameParser sẽ trả về Common Name thứ nhất, tức là www.google.com, và mặc kệ Common Name thứ hai. Nhưng liệu có thư viện nào trả về kết quả thứ hai hay không? Khi đó chúng ta sẽ có một hướng tấn công mới, giống như HTTP Paramater Pollution.

Có rất nhiều thư viện chịu trách nhiệm kiểm tra Common Name trong certificate. Tôi coi qua một vòng, thấy có những thư viện chấp nhận Common Name cuối cùng, nhưng cũng có thư việc chấp nhận tất cả Common Name. Vài ví dụ:
- Java chấp nhận Common Name đầu tiên.
- GoLang chấp nhận Common Name cuối cùng.
- BoringSSL chấp nhận tất cả.

Trong đầu tôi lúc đó hình dung ra một các tấn công như sau:
1/ Tạo một Certificate Signing Request (CSR) có chứa hai Common Name: www.tetcon.org và www.google.com theo thứ tự đó.
2/ Đi tìm một Certificate Authority ký CSR của tôi, với hi vọng rằng họ sẽ giữ nguyên Common Name, nhưng chỉ kiểm tra sở hữu tên miền thứ nhất. Do đó tôi sẽ có được một certificate có hai Common Name.
3/ Sử dụng certificate tạo ra ở bước 2/ để đánh lừa GoLang và BoringSSL. Nếu đánh lừa được BoringSSL tức là đánh lừa được Chrome.

Nói cách khác tôi yêu cầu Certificate Authority cấp một certificate cho tên miền www.tetcon.org, thuộc sở hữu của tôi, nhưng tôi có thể sử dụng certificate đó cho www.google.com.

Tối hôm đó về nhà tôi tìm cách tạo ra một CSR có hai Common Name. Certificate và CSR được định dạng theo chuẩn ASN.1. Thông thường người ta tạo ra CSR bằng cách sử dụng lệnh openssl req, nhưng tôi cho rằng lệnh này không cho phép tạo CSR có hai Common Name. Hoặc là tôi phải sửa lại mã nguồn của lệnh openssl req, hoặc là tôi phải tìm cách tạo ra CSR từ đầu. Tôi chọn phương án thứ hai, do trước đây tôi đã có sử dụng pyasn1 làm một việc tương tự. Tôi mất hơn bốn tiếng đồng hồ mới viết xong một script để tạo CSR như ý.

Bài học #1: hiểu công cụ của mình. Có một cách rất đơn giản để tạo ra CSR có hai Common Name. openssl req chấp nhận tham số "-subj". Tôi đã mất thời gian một cách vô ích vì không biết xài công cụ có sẵn.

Bạn nào muốn thử có thể chạy các lệnh sau đây để tạo ra một CSR có hai Common Name:

        openssl req -newkey rsa:2048 -sha256 -out multivalue_subject_cn.csr \
        -keyout /dev/null -nodes -subj "/C=US/ST=California/L=Mountain View/O=Google \
        Inc/CN=www.tetcon.orr/CN=www.google.com"
     
        openssl req -in multivalue_subject_cn.csr -verify -text
     
Dẫu sao thì tôi cũng tạo được một CSR như ý muốn. Bước tiếp theo là đi tìm một CA chịu ký CSR và giữ nguyên Distinguished Name. Tôi mất hai ngày, vài trăm đôla, nhưng chẳng thu được gì cả. Các CA, có vẻ rút kinh nghiệm từ các tấn công trước, đều tự tạo lại Distinguished Name, không chấp nhận giá trị nằm trong CSR của tôi. Nhưng cho đến lúc đó tôi vẫn tin là trong vô vàn CA thể nào cũng có một CA giữ nguyên Distinguished Name.

Vấn đề là dẫu tôi có nhận được một certificate với hai Common Name, tôi không thể dùng nó ở đâu cả. Nếu bạn quay lại lên trên để xem lại hàm verifyHostname sẽ thấy nó chỉ kiểm tra Common Name khi certificate không có mục SubjectAltName. Khi CA tạo ra một certificate mới, lúc nào họ cũng chép Common Name vào mục SubjectAltName. Vẫn có khả năng CA chép cả hai Common Name vào, nhưng tôi chưa tìm thấy cái nào như vậy và khả năng cao là không có.

Sai lầm ở đây là tôi đã tập trung hoàn toàn vào chuyện đi tìm cách khai thác lổ hổng, nhưng lại không nghĩ đến những tình huống có thể khiến lổ hổng của tôi bị vô hiệu hóa. Tôi nhìn vào đoạn mã của hàm verifyHostname nhưng chỉ tập trung vào lổ hổng, bỏ qua điều kiện để lổ hổng có thể được khai thác. Ở đây, tôi bị mắc vào confirmation bias, chỉ muốn đi tìm bằng chứng ủng hộ cho giả thuyết của mình, một sai lầm nguy hiểm khi làm nghiên cứu và cả trong cuộc sống hàng ngày.

Bài học #2: phải thử sai (falsify) ý tưởng của mình. Phải thử tất cả những tình huống ý tưởng không chạy được. Như một giáo sư từng nào, thất bại trong nghiên cứu là bình thường, nhưng phải thất bại càng nhanh càng tốt! Đừng bỏ ra cả đống thời gian và tiền bạc rồi mới phát hiện ra nghiên cứu của mình bất khả thi.

Có một cách đơn giản và miễn phí để thử sai ý tưởng tấn công của tôi. Tôi có thể tự tạo một CA, cấu hình Chrome để nó tin tưởng CA, rồi dùng CA ký một certificate có hai Common Name, có hay không có SubjectAltName. Ngay lập tức tôi sẽ biết liền Chrome sẽ ứng xử ra sao, mà không phải tốn tiền hay thời gian.

Sai lầm lớn nhất của tôi là không tìm và đọc các kết quả nghiên cứu trước đó (ví dụ như http://www.ioactive.com/pdfs/PKILayerCake.pdf hoặc http://wiki.cacert.org/VhostTaskForce#Interoperability_Test). Khi phát hiện ra hướng tấn công này, tôi đã nghĩ chắc nó không mới đâu. Tôi biết chưa ai tìm thấy bất kỳ lỗi nào thuộc dạng tấn công này, nhưng thay vì kết luận người ta thử rồi nhưng không khai thác được, tôi lại kết luận (hơi ngông) chắc chưa ai tìm được lỗi nào hết. Nếu tôi chịu khó tìm khoảng 5'-10', chắc chắn tôi đã hiểu tại sao không có lỗi nào được phát hiện, trước khi vùi đầu vùi cổ đi tìm.

Bài học #3: hiểu nghiên cứu của mình. Trước khi bắt tay vào triển khai bất kỳ ý tưởng nào, hãy thử tìm xem có ai nói về ý tưởng này chưa, và nếu có, người ta nói cái gì. Tìm chừng vài phút trên Google có khi sẽ tiết kiệm được khối thời gian và tiền bạc đầu tư vào một ý tưởng chẳng dẫn đến đâu.

--

Nói chung là thất bại ê chề, nhưng cũng vui. Tiền thì công ty trả, nhưng tôi đang tìm cách đi đòi refund, không biết bọn CA có trả lại hay không nữa @_@.

Wednesday, March 16, 2016

Viet InfoSec Mailing List

Sau TetCon 2016, nhiều người đề nghị với tôi rằng nên có một mailing list để những ai tham dự TetCon có một nơi chia sẻ và trao đổi các vấn đề an toàn thông tin.

Tôi nghĩ đây là một ý hay và hôm nay đã tạo list Viet InfoSec. Viet InfoSec là một diễn đàn mở cho tất cả những ai quan tâm đến an toàn thông tin ở Việt Nam và trên thế giới. Tiếng Việt là ngôn ngữ chính của list, nhưng tiếng Anh cũng được chào đón.

Nhấn vào đây để tham gia: https://groups.google.com/forum/#!forum/viet-infosec.

--

After TetCon 2016, many people have suggested creating a list on which TetCon attendants can discuss and share information security news and whatever.

I think this is a pretty good idea, and decided to create this list. Viet Infosec is an open forum for anyone interested in information security, in Vietnam and around the world. Vietnamese is the primary language of the list, but English is also welcome.

Click here to join: https://groups.google.com/forum/#!forum/viet-infosec.

Asiacrypt 2016 lần đầu tiên được tổ chức ở Hà Nội

Thông tin chính thức: http://www.asiacrypt2016.com/.

Asiacrypt là một trong ba hội thảo chính của Hiệp Hội Nghiên Cứu Mật Mã Quốc Tế (International Association for Cryptologic Research). Nhờ sự vận động của anh Phan Dương Hiệu, anh Ngô Bảo Châu và những anh chị khác trong ban tổ chức, năm nay lần đầu tiên hội thảo sẽ được tổ chức ở Hà Nội, từ ngày 4 đến ngày 8 tháng 12 năm 2016.

Ngoài chương trình chính thức, một tuần trước hội thảo ban tổ chức (dự kiến) sẽ tổ chức các lớp học với chủ đề “Cryptography: Foundations and New Trends”. Tất cả các lớp học đều miễn phí. Ban tổ chức dự kiến, nếu kinh phí cho phép, tài trợ chi phí đi lại, ăn ở cho các sinh viên Việt Nam ở xa.

Theo nguồn tin riêng của tôi (tức là nghe anh Hiệu nói) nếu không có gì thay đổi vào giờ chót, djb, Koblitz, Phong Q Nguyen, v.v. sẽ dạy high-speed cryptography, post-quantum cryptography, elliptic curve cryptography, lattice-based cryptography, v.v. Không có gì sướng bằng được học mật mã từ chính những người sáng chế ra chúng!

Để có thể tổ chức chu đáo hội thảo và các lớp học, ban tổ chức đang tìm kiếm các nhà tài trợ. Nếu công ty của bạn muốn tài trợ Asiacrypt, xin vui lòng liên hệ với tôi ở địa chỉ thaidn@gmail.com. Với sự tham gia của những tên tuổi lớn trong ngành mật mã học, Asiacrypt 2016 sẽ thu hút đông đảo các nhà nghiên cứu đầu ngành, các sinh viên, kỹ sư tài năng trong và ngoài nước. Đây là cơ hội tuyệt vời để quảng bá công ty, tìm kiếm nhân lực, tạo dựng mối quan hệ với các chuyên gia hàng đầu thế giới.

Wednesday, March 2, 2016

Diffie & Hellman win the Nobel prize of computer science, yay!

http://www.nytimes.com/2016/03/02/technology/cryptography-pioneers-to-win-turing-award.html

Some fun facts:
- If you're living in the South SF Bay, DH was invented in a room near you.
- DH was invented before RSA, yet RSA won Turing Award more than a decade earlier.
- GCHQ, the NSA of UK, claimed that they had invented public key crypto two years earlier than DH, but Diffie didn't think so.
- While RSA is becoming obsolete, DH is and will be the backbone of Internet security for years to come. Whenever you connect to Google or Facebook, you're using DH.
- DH used a math trick that nobody knows how hard it really is. It must be very hard because nobody knows how to solve it in the last 40 years (modulo some discoveries that decrease its hardness).
- But the trick is surprisingly simple. Any sixth grader can understand how it works.
- Hellman was a Stanford professor, but Diffie was a software engineer that happened to love crypto. My chance of winning the award suddenly has increased from zero to epsilon =)