<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5896983951610053372</id><updated>2012-01-28T17:11:40.818+07:00</updated><category term='sandbox'/><category term='barcamp'/><category term='cloud computing'/><category term='python'/><category term='distributed computing'/><category term='hadoop'/><category term='life'/><title type='text'>Nam Nham's blog</title><subtitle type='html'>&amp;gt;&amp;gt;&amp;gt;  Life and Technology Review</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>7</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-3295087674349909462</id><published>2012-01-15T20:50:00.000+07:00</published><updated>2012-01-15T20:50:24.180+07:00</updated><title type='text'>Mua hàng không mất tiền - Lỗ hổng trong một số cổng thanh toán trực tuyến ở Việt Nam</title><content type='html'>&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Đây là bài tham luận tôi đã trình bày tại &lt;a href="http://www.tetcon.org/"&gt;TetCon&lt;/a&gt; 2012. Nội dung của bài này sẽ được đăng lên trang chủ của hội thảo. Tôi post lại ở đây để làm kỉ niệm.&amp;nbsp;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Lỗ hổng này tôi đã tình cờ phát hiện được trong khi đang phát triển một dịch vụ có sử dụng API của một cổng thanh toán trực tuyến. Lỗ hổng này về mặt kỹ thuật thì không có gì mới và cũng không phức tạp cho lắm. Tôi cũng khá ngạc nhiên là lỗ hổng này được lập lại ở nhiều cổng thanh toán trực tuyến khác nhau. Vì một số lý do nên tôi không nêu tên cụ thể các cổng thanh toán trực tuyến, nhưng nếu bạn có làm việc trực tiếp với họ thì bạn sẽ biết được tên các cổng thanh toán trực tuyến này. Do thời gian có hạn nên tôi đã không tìm hiểu hết các cổng thanh toán trực tuyến đang hoạt động ở Việt Nam. Tuy nhiên dựa vào nội dung của bài tham luận này bạn có thể biết được cổng thanh toán mà bạn đang phát triển có nằm trong trường hợp này hay không.&amp;nbsp;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;----------&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;b&gt;Tóm tắt&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Thanh toán trực tuyến là một trong những loại hình dịch vụ phát triển mạnh nhất ở Việt Nam trong vài năm vừa qua. Bây giờ chỉ với một chiếc thẻ nội địa hay thẻ tín dụng, bạn có thể mua và thanh toán được rất nhiều mặt hàng khác nhau, từ quần áo, sách vở, vé xem film cho đến vé máy bay. Có thật sự là phải cần có thẻ mới mua được hàng? Trong bài tham luận này, chúng tôi sẽ trình diễn một cách mua hàng không mất tiền, bằng cách khai thác lỗ hổng an ninh trong một vài hệ thống thanh toán trực tuyến phổ biến ở Việt Nam. Những lỗ hổng này đã được thông báo đến các bên liên quan trước khi bài tham luận này được gửi đến TetCon 2012.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;1. Giới thiệu&lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Cùng với sự phát triển của thương mại điện tử, sự ra đời của các cổng thanh toán trực tuyến là một nhu cầu tất yếu. Cổng thanh toán đóng vai trò quan trọng trong việc đem đến sự giao dịch thuận tiện giữa người mua và người bán. Ngoài việc giúp cho giao dịch giữa người bán và người mua được tiến hành thuận tiện, việc đảm bảo an toàn cho các giao dịch này là một yêu cầu bắt buộc.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Trong bài tham luận này, chúng tôi sẽ tập trung phân tích một cơ chế hoạt động phổ biến trong các cổng thanh toán trực tuyến hiện nay ở Việt Nam. Trong cơ chế này, 3 thành phần cơ bản tham gia vào quá trình thanh toán gồm có người mua (customer), địa chỉ bán hàng (merchant's site) và cổng thanh toán (payment gateway). Dòng chảy dữ liệu giữa các thành phần này được mô tả như trong hình 1.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;b id="internal-source-marker_0.4286409141495824"&gt;&lt;img height="225px;" src="https://docs.google.com/drawings/image?id=sxOfByKFgmv7z9L4YzoEVDw&amp;amp;w=520&amp;amp;h=225&amp;amp;rev=138&amp;amp;ac=1" width="520px;" /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;Hình 1. Dòng chảy dữ liệu của quá trình mua bán thông qua cổng thanh toán&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Sau khi người mua vào website của người bán chọn lựa mặt hàng cần mua và đồng ý thực hiện việc thanh toán, quá trình thanh toán sẽ diễn ra như sau:&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (1): Trình duyệt của người mua hàng sẽ gởi yêu cầu thanh toán về máy chủ trang web bán hàng. Thông tin được gởi về có thể bao gồm: mã đơn hàng, danh sách các mặt hàng, tổng số tiền cần thanh toán,...&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (2): Ứng dụng web của người bán hàng sẽ xử lý đơn hàng và sẽ trả kết quả về cho người mua hàng dưới dạng một yêu cầu chuyển hướng HTTP (HTTP redirect). Đích đến của yêu cầu chuyển hướng này là địa chỉ của cổng thanh toán. Thông tin trong yêu cầu chuyển hướng có thể bao gồm định danh của đơn vị bán hàng, mã đơn hàng, số tiền cần thanh toán, địa chỉ trả về kết quả nếu việc thanh toán thành công,... Ngoài ra, để đảm bảo cho cổng thanh toán xác định được rằng yêu cầu gởi đến này được tạo ra từ ứng dụng của người bán hàng, dữ liệu được gởi đi bao gồm một chữ ký của bên bán hàng trên các thông tin còn lại. Chúng tôi sẽ mô tả về các tạo ra chữ ký này trong phần tiếp theo.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (3): Trình duyệt của người mua hàng sau khi nhận được yêu cầu chuyển hướng từ phía người bán sẽ tự động chuyển đến trang web của cổng thanh toán. Ứng dụng web của cổng thanh toán sẽ tiếp nhận yêu cầu này và bắt buộc người mua hàng phải thực hiện các thao tác trên cổng thanh toán như đăng nhập, điền thông tin thẻ tín dụng hoặc ATM, xác nhận đơn hàng,...&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (4): Sau khi người mua hàng thực hiện thành công các bước theo đúng quy trình của cổng thanh toán, phía cổng thanh toán sẽ trả về kết quả cho người mua hàng dưới dạng một yêu cầu chuyển hướng HTTP. Đích đến của yêu cầu chuyển hướng này là địa chỉ máy chủ của trang web bán hàng (địa chỉ này được gởi đến cổng thanh toán như ở bước 2). Thông tin đi kèm trong yêu cầu chuyển hướng này dùng để xác nhận với trang web bán hàng rằng người mua đã thanh toán thành công. Các thông tin này cũng được đi kèm với một chữ ký như ở trong bước 2.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (5): Trình duyệt của người mua hàng sẽ tự động chuyển hướng trang web bán hàng sau khi nhận yêu cầu chuyển hướng từ cổng thanh toán như trong bước 4.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Bước (6): Trang web bán hàng sẽ kiểm tra thông tin được gởi đến. Nếu thông tin này có nội dung mô tả đúng như khi khách hàng đã thanh toán đơn hàng và có chữ ký hợp lệ thì giao dịch được thực hiện thành công.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Ưu điểm của quy trình này là ngắn gọn và đơn giản. Nó đem lại sự thuận tiện cho người dùng. Tuy nhiên việc hiện thực nó không đúng có thể tạo ra một lỗ hổng nghiêm trọng giúp cho một người có thể thực hiện mua hàng mà không cần phải thanh toán tiền. Trong bài tham luận này, chúng tôi sẽ phân tích lỗ hổng trong một cách hiện thực của của cơ chế thanh toán này. Lỗ hổng này có thể khai thác được và được tìm thấy trong một số cổng thanh toán trực tuyến phổ biến ở Việt Nam.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Một cơ chế tạo chữ ký không an toàn&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Trong mô hình thanh toán được mô tả như phần trên, để có thể xác thực được các thông điệp được gởi qua lại, website bán hàng thường được cổng thanh toán cung cấp cho một mã định danh (&lt;i&gt;merchant code&lt;/i&gt;) và một khóa chia sẻ chung bí mật (&lt;i&gt;shared secret key&lt;/i&gt;). Khóa bí mật này dùng để xác thực các thông điệp được trao đổi giữa các bên.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Trong một số cổng thanh toán chúng tôi đã tiến hành khảo sát, quá trình tạo ra chữ ký cho các thông điệp được thực hiện như sau:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Sắp xếp các thông số được truyền trong thông điệp theo thứ tự bảng chữ cái dựa trên tên của thông số. Ví dụ: &lt;i&gt;order_id=123&lt;/i&gt;, &lt;i&gt;merchant_id=1230&lt;/i&gt;, &lt;i&gt;amount=100000&lt;/i&gt; được sắp xếp thành &lt;i&gt;amount=100000&lt;/i&gt;, &lt;i&gt;merchant_id=1230&lt;/i&gt;, &lt;i&gt;order_id=123&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Kết hợp khóa bí mật và giá trị của các thông số đã được sắp xếp thành một chuỗi ký tự. Ví dụ: &lt;i&gt;SECRET1000001230123&lt;/i&gt;.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Tính giá trị băm của chuỗi này bằng thuật toán MD5 (hoặc SHA1)&lt;/li&gt;&lt;li&gt;Thêm giá trị băm này vào danh sách các tham số được gởi đi như là một chữ ký xác thực. Ví dụ: &lt;i&gt;signature=7BD70B91F6F026FBFFFA552A7D59B5BD&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="text-align: justify;"&gt;Bên nhận được thông điệp cũng thực hiện lại quá trình này nhưng sử dụng khóa bí mật được lưu trữ tại hệ thống của mình trong bước 2. Nếu chữ ký được tạo ra giống với chữ ký được gởi đến thì thông điệp được xem là hợp lệ và tiếp tục được xử lý như một giao dịch bình thường.&lt;/div&gt;&lt;br /&gt;Việc tạo ra chữ ký theo phương pháp này có thể bị tấn công bằng một số cách sau:&lt;br /&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;Do không có dấu phân cách giữa các giá trị và tên của tham số không được sử dụng trong việc tạo ra chữ ký điện tử, nên chữ ký được tao ra cho danh sách tham số &lt;i&gt;amount=100000&amp;amp;merchant_id=1230&amp;amp;order_id=123&lt;/i&gt; sẽ giống với chữ ký được tạo ra cho &lt;i&gt;amount=100000&amp;amp;order_id=123&amp;amp;status=0&amp;amp;tranx_id=123&lt;/i&gt;.&lt;/li&gt;&lt;li style="text-align: justify;"&gt;Do MD5 có thể bị tấn công bằng phương pháp mở rộng chiều dài (length-extension attack), một người có thể chèn thêm dữ liệu bất kỳ vào cuối thông điệp mà có thể tạo ra chữ ký xác thực hợp lệ mà không cần phải biết khóa bí mật. Chúng tôi sẽ nói về cách tấn công này trong phần tiếp theo.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Trong một số cổng thanh toán trực tuyến mà chúng tôi tiến hành khảo sát, một số có thể bị tấn công bằng cách thứ nhất, một số có thể bị tấn công bằng phương pháp thứ hai. Bằng cách khai thác được một trong hai cách này, một người có thể làm giả một thông điệp được gởi từ cổng thanh toán trực tuyến xác nhận rằng người mua đã thanh toán tiền và gởi thông điệp giả mạo này về cho website bán hàng. Và như vậy, người này có thể mua hàng thành công mà không cần phải thông qua cổng thanh toán trực tuyến và không cần phải mất tiền.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Tấn công mở rộng chiều dài trên MD5 (Length-Extension Attack)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Tấn công mở rộng chiều dài là một loại tấn công khá phổ biến đối với các hàm băm được xây dựng trên cấu trúc lặp Merkle-Damgård [1] như MD0-MD5 và SHA0-SHA2. Với phương pháp tấn công này, một người có thể dựa trên giá trị băm h(m) và chiều dài len(m) của thông điệp m để tính giá trị băm h(m||pad(m)||m') với bất kỳ thông điệp m' nào. Tham khảo [2] có mô tả về dạng tấn cống này trên API của một dịch vụ chia sẻ ảnh khá phổ biến là Flickr.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Trong các hàm băm được xây dựng trên cấu trục lặp Merkle-Damgård, thông điệp đầu vào được chia ra thành một chuỗi các khối (block) có kích thước bằng nhau và được xử lý theo thứ tự bằng một hàm nén một chiều (one-way compression function). Trong thuật toán MD5, hàm nén nhận vào 2 giá trị - một giá trị móc nối (chaining value) có kích thước 128-bit và một khối (block) thông điệp có kích thước 512-bit - và tạo ra một giá trị móc nối 128-bit khác được sử dụng làm đầu vào cho bước lặp tiếp theo. Thông điệp ban đầu được đệm (padded) để có kích thước là một bội số của 512-bit và được chia thành một chuỗi các khối có kích thước 512-bit. Hàm nén được tính một cách lặp lại với một giá trị móc nối ban đầu và khối thông điệp đầu tiên. Sau khi khối thông điệp cuối cùng được xử lý, giá trị móc nối cuối cùng là kết quả hàm băm của thông điệp ban đầu.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;b id="internal-source-marker_0.4286409141495824"&gt;&lt;img height="187px;" src="https://lh3.googleusercontent.com/j74ed1744HnFyszNGr2a4acWqLhMhpL-GYBCK0QizHcr2ysYVQMVunbUOUn8NHiE4tGnm5lJhIvXxrQFL5TRr5Nhzbi_aA4-juDUWHlUWY69-_Y_w4Y" width="400px;" /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;Hình 2. Cấu trúc lặp Merkle-Damgård (sao chép từ Wikipedia)&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Do cấu trúc lặp của thuật toán, một người có thể chỉ dựa vào giá trị băm và chiều dài của một thông điệp để tính giá trị băm của một thông điệp dài hơn được bắt đầu bằng thông điệp ban đầu, bao gồm cả giá trị đệm đã được thêm vào để cho thông điệp ban đầu có kích thước là một bội số của 512-bit (hình 3). Vấn đề này đã được mô tả trong [3].&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;&lt;b id="internal-source-marker_0.4286409141495824"&gt;&lt;img height="252px;" src="https://lh4.googleusercontent.com/JEn_1tEz8pKkznLUYKIPr4DrjykxEq1lPwOKcwkqliiULGEbUI4PPwsluggPH_6LQ9x04N6z4RamZwxOOnnsb5yn_k4126jJATpJprpNgODPTELbkYE" width="480px;" /&gt;&lt;/b&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: center;"&gt;Hình 3. Tấn công mở rộng chiều dài (sao chép từ [4])&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Đối với cơ chế tạo chữ ký như đã được mô tả trong phần 2, chúng ta có thể sử dụng phương pháp tấn công mở rộng chiều dài để tính chữ ký của bất kỳ thông điệp m' nào với m' bắt đầu bằng m||p, với p là giá trị được đệm vào SECRET||p trong cấu trúc lặp Merkle-Damgård.&lt;/div&gt;&lt;blockquote class="tr_bq"&gt;&lt;div style="text-align: center;"&gt;signature1 = MD5(SECRET||m)&lt;/div&gt;&lt;div style="text-align: center;"&gt;signature2 = MD5(SECRET||m||p||x)&lt;/div&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Ví dụ, dựa trên thông điệp yêu cầu chuyển hướng được gởi từ website bán hàng về cho khách hàng (như trong bước 2 của hình 1), một người có thể làm giả một thông điệp xác nhận thanh toán thành công được gởi về từ cổng thanh toán (như trong bước 4 của hình 1), và gởi thông điệp này đến website bán hàng để hoàn tất việc mua hàng.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;blockquote class="tr_bq"&gt;response1 = “amount=100000&amp;amp;merchant_id=1230&amp;amp;order_id=567&amp;amp;signature=[sig1]”&lt;br /&gt;m1 = “1000001230567"&lt;br /&gt;sig1 = MD5(SECRET || m1)&lt;br /&gt;x = 10000056701156&lt;br /&gt;m2 = m1 || p1 || x&lt;br /&gt;sig2 = MD5(SECRET || m2)&lt;br /&gt;response2 = “aaa=[m1||p1]&amp;amp;amount=100000&amp;amp;order_id=567&amp;amp;status=0&amp;amp;tranx_id=1156”&lt;/blockquote&gt;&lt;br /&gt;&lt;b&gt;4. Phương án vá lỗi đề nghị&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Do bản chất của lỗ hổng này là như nhau nên chúng tôi đề xuất phương án vá lỗi được mô tả trong phần 5.5 của tham khảo [2]. Bạn đọc quan tâm có thể tìm hiểu thêm trong tài liệu này.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;5. Kết luận&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Trong bài tham luận này chúng tôi đã mô tả về một lỗ hổng mật mã xuất hiện trong một số cổng thanh toán trực tuyến ở Việt Nam. Bằng việc khai thác lỗ hổng này, một người có thể mua hàng nhưng không cần phải trả tiền. Điều này có thể gây tổn hại rất lớn đến cổng thanh toán trực tuyến cũng như &amp;nbsp;các website bán hàng có liên quan. Do tính chất nhạy cảm của vấn đề, chúng tôi quyết định không nêu tên cụ thể của cổng thanh toán và chi tiết về cơ chế hoạt động của các cổng thanh toán này trong bài viết.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Lỗ hổng được trình bày trong bài viết đã được biết đến từ rất lâu trong cộng đồng làm về mật mã học (xem [5]). Tuy nhiên sau nhiều năm, vẫn còn rất nhiều website gặp phải lỗ hổng này. Trên thế giới, lỗ hổng này được tìm thấy ở một dịch vụ chia sẻ ảnh phổ biến là Flickr vào năm 2009 (xem [2]). Và một cách tình cờ, chúng tôi tìm thấy được lỗ hổng này xuất hiện trong một số cổng thanh toán trực tuyến phổ biến ở Việt Nam. Do không có đủ thời gian và nguồn lực, chúng tôi đã không kiểm tra trường hợp này đối với tất cả các cổng thanh toán cũng như các dịch vụ khác. Nhưng qua bài viết này, chúng tôi hi vọng rằng các đơn vị đang phát triển dịch vụ trực tuyến ở Việt Nam có cái nhìn cẩn trọng hơn trong việc hiện thực các chức năng liên quan đến mật mã học nhằm đem đến những sản phẩm tốt và an toàn cho người dùng.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;6. Tham khảo&lt;/b&gt;&lt;br /&gt;[1] http://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction&lt;br /&gt;[2] Thai Duong, Juliano Rizzo. Flickr’s API Signature Forgery Vulnerability, September 2009.&lt;br /&gt;[3] B. Kaliski and M. Robshaw. Message Authentication with MD5. RSA Labs' CryptoBytes, Vol. 1 No. 1, Spring 1995.&lt;br /&gt;[4] H. Travis. Web 2.0 Cryptology, A Study in Failure. OWASP, 2009. Retrieved September 13, 2009, from http://www.subspacefield.org/security/web_20_crypto.pdf.&lt;br /&gt;[5] &amp;nbsp;G. Tsudik. Message authentication with one-way hash functions. ACM Computer Communications Review, 22(5):29–38, 1992.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-3295087674349909462?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/3295087674349909462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2012/01/mua-hang-khong-mat-tien-lo-hong-trong.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3295087674349909462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3295087674349909462'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2012/01/mua-hang-khong-mat-tien-lo-hong-trong.html' title='Mua hàng không mất tiền - Lỗ hổng trong một số cổng thanh toán trực tuyến ở Việt Nam'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-775166303942674412</id><published>2010-03-17T00:34:00.163+07:00</published><updated>2011-05-03T16:21:24.762+07:00</updated><title type='text'>CodeGate 2010 CTF - Challenge 8: Bit-flipping attack on CBC mode</title><content type='html'>&lt;div style="text-align: justify;"&gt;This is a web-based cryptography challenge. In this challenge, we were provided a URL and a hint&amp;nbsp;"&lt;i&gt;the first part is just an IV&lt;/i&gt;".&lt;br /&gt;The URL is: &lt;a href="http://ctf1.codegate.org/99b5f49189e5a688492f13b418474e7e/web4.php"&gt;http://ctf1.codegate.org/99b5f49189e5a688492f13b418474e7e/web4.php&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;Analysis&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Go to the challenge URL. It will ask you the username for the first time. After we enter a value, for example '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;namnx&lt;/span&gt;', it will return only a single message "&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Hello, namnx!&lt;/span&gt;". Examine the HTTP payload, we will see the cookie returned:&lt;br /&gt;&lt;pre name="code"&gt;web4_auth=1vf2EJ15hKzkIxqB27w0AA==|5X5A0e3r48gXhUXZHEKBa5dpC+XfdVv4oamlriyi5yM=&lt;br /&gt;&lt;/pre&gt;The cookie includes 2 parts delimited by character '|'. After base64 decode the first part of the cookie, we have a 16-byte value. According to the hint, this is the IV of the cipher. And because it has 16-byte length, I guess that this challenge used AES cipher, and the block size is 16 bytes. Moreover, the cipher has an IV, so it can't be in ECB mode. I guessed it in CBC mode.&amp;nbsp;The last part is the base64 of a 32-byte value. This is a cipher text. We will exploit this value later.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Browse the URL again, we will receive another message: "&lt;i&gt;Welcome back, namnx! Your role is: user. You need admin role.&lt;/i&gt;" Take a look into this message, we can guess the operation of this app: it will receive the cookie from the client, decrypt it to get the user and role information and return the message to the client based on the user and role information. So, in order to get further information,&amp;nbsp;we must have the admin role. This is our goal in this challenge.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;Exploit&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;I wrote some Python to work on this challenge easier:&lt;br /&gt;&lt;pre name="code" class="python"&gt;import urllib, urllib2&lt;br /&gt;import base64, re&lt;br /&gt;&lt;br /&gt;url = 'http://ctf1.codegate.org/99b5f49189e5a688492f13b418474e7e/web4.php'&lt;br /&gt;user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'&lt;br /&gt;&lt;br /&gt;def get_cookie(user):&lt;br /&gt;    headers = { 'User-Agent' : user_agent}&lt;br /&gt;    values = {'username' : user, 'submit' : "Submit"}&lt;br /&gt;    data = urllib.urlencode(values)&lt;br /&gt;    request = urllib2.Request(url, data, headers)&lt;br /&gt;    response = urllib2.urlopen(request)&lt;br /&gt;    cookie = response.info().get('Set-Cookie')&lt;br /&gt;    groups = re.match("web4_auth=(.+)\|(.+);.+", cookie).groups()&lt;br /&gt;    iv = base64.b64decode(groups[0])&lt;br /&gt;    cipher = base64.b64decode(groups[1])&lt;br /&gt;    return iv, cipher&lt;br /&gt;&lt;br /&gt;def get_message(iv, cipher):&lt;br /&gt;    cookie = base64.b64encode(iv) + '|' + base64.b64encode(cipher)&lt;br /&gt;    cookie = urllib.quote(cookie)&lt;br /&gt;    cookie = 'web4_auth=' + cookie&lt;br /&gt;    headers = { 'User-Agent' : user_agent, 'Cookie': cookie}&lt;br /&gt;    request = urllib2.Request(url, None, headers)&lt;br /&gt;    response = urllib2.urlopen(request)&lt;br /&gt;    data = response.read()&lt;br /&gt;    print repr(data)&lt;br /&gt;    groups = re.match(".+, (.*)! .+: (.*)\. You.+", data).groups()&lt;br /&gt;    return groups[0], groups[1]&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The first function, &lt;b&gt;get_cookie&lt;/b&gt; will submit a value as a username in the first visit to the page, get the returned cookie, and then parse it to get the IV and cipher. The second function, &lt;b&gt;get_message&lt;/b&gt;, do the task like when you visit the page in later times, it parses the response message to get the returned username and role.&lt;/div&gt;&lt;br /&gt;Let do some test cases:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&gt;&gt;&gt; iv, cipher = get_cookie('123456789012')&lt;br /&gt;&gt;&gt;&gt; len(cipher)&lt;br /&gt;32&lt;br /&gt;&gt;&gt;&gt; iv, cipher = get_cookie('1234567890123')&lt;br /&gt;&gt;&gt;&gt; len(cipher)&lt;br /&gt;48&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;When you input the user with a 12-byte value, the returned cipher will have 32 bytes (2 blocks). And when you enter a 13-byte value, the cipher will have 48 bytes (3 blocks). This means that beside the username value, the plain text of the cipher will be added more 20 bytes.&lt;/div&gt;&lt;br /&gt;Try altering the cipher text to see how it is decrypted:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&gt;&gt;&gt; iv, cipher = get_cookie('1234567890')&lt;br /&gt;&gt;&gt;&gt; cipher1 = cipher[:-1] + '\00'&lt;br /&gt;&gt;&gt;&gt; username, role = get_message(iv, cipher1)&lt;br /&gt;'Welcome back, 1234567\xa2\xc2\xca\xfei\xdb\xee_c\xa7\xd7\x0c\xa9j\xe0\xbb! Your role is: . You need admin role.'&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;When we altered the last block of the cipher, just first 7 characters of the username is decrypted correctly. So the format of the plain text maybe like this: [9 bytes] + &lt;b&gt;username&lt;/b&gt;&amp;nbsp;+ [11 bytes].&lt;/div&gt;&lt;br /&gt;Now we'll try to determine the first 9 bytes of the plain text:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&gt;&gt;&gt; iv, cipher = get_cookie('1234567890123456')&lt;br /&gt;&gt;&gt;&gt; cipher1 = cipher[:32] + iv + cipher[:16]&lt;br /&gt;&gt;&gt;&gt; username, role = get_message(iv, cipher1)&lt;br /&gt;'Welcome back, 1234567890123456! Your role is: E\x9bpY?\xfbW6\x84{\x8fn\x1e\x80\x10\x1busername=1234567. You need admin role.'&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;As you can see, the last block of the decrypted role is the first block of the plain text. So, the format of the plain text may be: '&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="color: blue;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;username=&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;' + &lt;b&gt;username&lt;/b&gt; + [11 bytes].&lt;/div&gt;&lt;br /&gt;To here, we can guess that the format of the plain text can be something like:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;'&lt;span class="Apple-style-span" style="color: blue;"&gt;username=&lt;/span&gt;' + username + [delimiter] + [param] + '&lt;span class="Apple-style-span" style="color: blue;"&gt;=&lt;/span&gt;' + [value]&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;The last 11 bytes of the plain text can be determined by the code below:&lt;br /&gt;&lt;pre name="code" class="python"&gt;&gt;&gt;&gt; iv, cipher = get_cookie('\x00')&lt;br /&gt;&gt;&gt;&gt; username, role = get_message(iv, cipher)&lt;br /&gt;'Welcome back, \x00##role=user\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00! Your role is: . You need admin role.'&lt;br /&gt;&lt;/pre&gt;You can see the last 11 bytes of the plain text in the returned message. So, at this time, we can conclude format of the plain text is:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;'&lt;span class="Apple-style-span" style="color: blue;"&gt;username=&lt;/span&gt;' + username + '&lt;span class="Apple-style-span" style="color: blue;"&gt;##role=&lt;/span&gt;' + role&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Now, the last thing we have to do is altering the role value to 'admin'. Because we've already known the format of the plain text, we can choose to input the username close to the target plain text and try to alter the cipher text in the way that the decrypted value is what we want.&lt;/div&gt;&lt;br /&gt;Let remind the operation of CBC mode in cryptographic ciphers. In&amp;nbsp;encryption process:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;y[1] = C(IV xor x[1])&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;y[n] = C(y[n-1] xor x[n])&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;and in the decryption:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;x[1] = D(y[1]) xor IV&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;x[n] = D(y[n]) xor y[n-1]&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Notice that if we flip one bit in the (n-1)th block of cipher text, the respective bit in the n-th block of plain text will be also flipped. So, we will you this fact to exploit the challenge:&lt;/div&gt;&lt;pre name="code" class="python"&gt;&gt;&gt;&gt; iv, cipher = get_cookie('012345678901234567890123#role=admin')&lt;br /&gt;&gt;&gt;&gt; s = cipher[:16] + chr(ord(cipher[16]) ^ 0x10) + cipher[17:]&lt;br /&gt;&gt;&gt;&gt; username, role = get_message(iv, s)&lt;br /&gt;'Welcome back, 0123456L\xaa\x17m\xe9\x91\xdc\xe2`#z)\xd8m\xd8\x18! Your role is: admin. You need admin role. Congratulations! Here is your flag: the_magic_words_are_squeamish_ossifrage_^-^!!!!!'&lt;br /&gt;&lt;/pre&gt;Successful! Such an interesting challenge, isn't it?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;References&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;- Block cipher modes of operation: &lt;a href="http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation"&gt;http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation&lt;/a&gt;&lt;br /&gt;- Bit-flipping attack:&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Bit-flipping_attack"&gt;http://en.wikipedia.org/wiki/Bit-flipping_attack&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-775166303942674412?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/775166303942674412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2010/03/codegate-2010-ctf-challenge-8-cbc-mode.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/775166303942674412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/775166303942674412'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2010/03/codegate-2010-ctf-challenge-8-cbc-mode.html' title='CodeGate 2010 CTF - Challenge 8: Bit-flipping attack on CBC mode'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-4186880956650713744</id><published>2010-03-16T16:43:00.017+07:00</published><updated>2011-05-03T16:33:38.316+07:00</updated><title type='text'>CodeGate 2010 CTF - Challenge 7: Weak SSL Cracking</title><content type='html'>&lt;div style="text-align: justify;"&gt;Last weekend, I had a great hacking time with team &lt;a href="http://www.vnsecurity.net/about-us/clgt-ctf-team/"&gt;CLGT&lt;/a&gt; in the &lt;a href="http://ctf.codegate.org/"&gt;CodeGate 2010 CTF&lt;/a&gt; Preliminary Round. It lasted 36 consecutive hours from 7:00AM March 13 to 7:00PM March 14. There were a lot of teams around the world participating in this hacking contest. And excellently, CLGT proved it as one of the best teams when&amp;nbsp;got the 2nd place in this round. See &lt;a href="http://beist.org/CG2010_rank.png"&gt;final ranking&lt;/a&gt;.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This entry is my writeup for challenge 7. I think this is an interesting challenge from which you can learn more deeply about SSL protocol and public key cryptography. In this challenge, we were provided a tcpdump file of a SSL traffic and a hint "&lt;i&gt;does the modulus look familiar?&lt;/i&gt;". So our goal is to analyze and decrypt this captured traffic to get the flag.&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;Analysis&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Firstly, I used Wireshark to load this file and start to analyze it:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh3.ggpht.com/_BaefoYBtOwQ/S59Mv6OohsI/AAAAAAAAAW4/z7INUja_DtE/challenge7-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="216" src="http://lh3.ggpht.com/_BaefoYBtOwQ/S59Mv6OohsI/AAAAAAAAAW4/z7INUja_DtE/challenge7-1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;There are 26 packets captured. Packet #4 is a &lt;b&gt;&lt;i&gt;SSL Client Hello&lt;/i&gt;&lt;/b&gt; packet, but after it, packet #8 and packet #9 have FIN flag. This mean that the session was termininated. So we just ignore them.&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Packet #14 is another &lt;b&gt;&lt;i&gt;SSL Client Hello&lt;/i&gt;&lt;/b&gt; packet. This is where the real session began. Take a look into it:&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh4.ggpht.com/_BaefoYBtOwQ/S59PftmaEmI/AAAAAAAAAXA/yxCqiOSmyHA/challenge7-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="219" src="http://lh4.ggpht.com/_BaefoYBtOwQ/S59PftmaEmI/AAAAAAAAAXA/yxCqiOSmyHA/challenge7-2.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;There is nothing special. It is just a normal &lt;b&gt;&lt;i&gt;SSL Client Hello&lt;/i&gt;&lt;/b&gt; packet. It happens when a client want to connect to a SSL service. We continue look into the packet #16, the &lt;b&gt;&lt;i&gt;SSL Server Hello&lt;/i&gt;&lt;/b&gt; packet:&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_BaefoYBtOwQ/S59SI8VjnhI/AAAAAAAAAXI/LGU0BQZP4x0/s1600/challenge7-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="258" src="http://lh6.ggpht.com/_BaefoYBtOwQ/S59SI8VjnhI/AAAAAAAAAXI/LGU0BQZP4x0/s400/challenge7-3.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;This is the response for SSL Client Hello packet. We can see some useful information here:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;- The cipher suite will be used: &lt;b&gt;RSA_WITH_AES_256_CBC_SHA&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;- The X509 certificate of the server&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;In the SSL protocol, the server send its certificate to the client in the handshaking process. This certificate will be used for supporting the key exchange afterward. The certificate contains the server's public key and other data. By extracting the public key and recovering the private key from it, we can decrypt the SSL traffic.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', serif;"&gt;Exploit&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;I wrote some Python code to exploit this challange:&lt;/div&gt;&lt;pre name="code" class="python"&gt;from scapy.all import *&lt;br /&gt;from M2Crypto import X509&lt;br /&gt;&lt;br /&gt;def decode_serverhello(packet):&lt;br /&gt;    payload = packet.load&lt;br /&gt;    cert = payload[94:1141]&lt;br /&gt;    cert = X509.load_cert_string(cert, 0)&lt;br /&gt;    return cert&lt;br /&gt;&lt;br /&gt;def get_pubkey(cert):&lt;br /&gt;    pubkey = cert.get_pubkey().get_rsa()&lt;br /&gt;    n = long(pubkey.n.encode('hex')[8:], 16)&lt;br /&gt;    e = long(pubkey.e.encode('hex')[9:], 16)&lt;br /&gt;    return n, e&lt;br /&gt;&lt;br /&gt;packets = rdpcap('ssl.pcap')&lt;br /&gt;cert = decode_serverhello(packets[15])&lt;br /&gt;n,e = get_pubkey(cert)&lt;br /&gt;&lt;/pre&gt;Because this traffic used RSA as public key algorithm, the public key contains 2 components: &lt;b&gt;n&lt;/b&gt; and &lt;b&gt;e&lt;/b&gt;. We get their values from the above code:&lt;br /&gt;&lt;pre name="code" class="python"&gt;n = 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413&lt;br /&gt;e = 65537&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;In RSA, &lt;b&gt;n&lt;/b&gt; is the product of 2 big prime numbers &lt;b&gt;p&lt;/b&gt; and &lt;b&gt;q&lt;/b&gt;. So, in order to recover the RSA private key from the public key, we must factorize&amp;nbsp;&lt;b&gt;n&lt;/b&gt; into &lt;b&gt;p&lt;/b&gt; and &lt;b&gt;q&lt;/b&gt;. This is the key point of the challenge.&amp;nbsp;In this situation, n is a very big number (232 decimal digits).&amp;nbsp;How can we do that? In the beginning, I didn't know how to solve it. But I remembered the hint "&lt;i&gt;does the modulus look familiar?&lt;/i&gt;". So I tried &lt;a href="http://bit.ly/azg7Vh"&gt;googling it&lt;/a&gt; :-D (actually just its last digits). And... oh my god, I was lucky! It is &lt;a href="http://en.wikipedia.org/wiki/RSA_numbers#RSA-768"&gt;RSA-768&lt;/a&gt;. It's factorized just few months ago.&lt;/div&gt;&lt;pre name="code" class="python"&gt;RSA-768 = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489&lt;br /&gt;        × 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917&lt;br /&gt;&lt;/pre&gt;So now, we have all components of the RSA keys.&lt;br /&gt;&lt;pre name="code" class="python"&gt;n = 1230186684530117755130494958384962720772853569595334792197322452151726400507263657518745202199786469389956474942774063845925192557326303453731548268507917026122142913461670429214311602221240479274737794080665351419597459856902143413&lt;br /&gt;&lt;br /&gt;e = 65537&lt;br /&gt;&lt;br /&gt;p = 33478071698956898786044169848212690817704794983713768568912431388982883793878002287614711652531743087737814467999489&lt;br /&gt;&lt;br /&gt;q = 36746043666799590428244633799627952632279158164343087642676032283815739666511279233373417143396810270092798736308917&lt;br /&gt;&lt;br /&gt;d = 703813872109751212728960868893055483396831478279095442779477323396386489876250832944220079595968592852532432488202250497425262918616760886811596907743384527001944888359578241816763079495533278518938372814827410628647251148091159553&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The last thing we have to do is generating the RSA private key in PEM format from these components. But how can we do that? As far as I know, popular cryptographic libraries like OpenSSL do not support this. So&amp;nbsp;in this case, I wrote my own tool to do this task. It is based on ASN1. It is a little long to post here. But if you want to write your own one, I recommend &lt;a href="http://pyasn1.sourceforge.net/"&gt;pyasn1&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;After having the private key, just import it to Wireshark to decrypt the SSL traffic:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://lh6.ggpht.com/_BaefoYBtOwQ/S59zDsyIwPI/AAAAAAAAAXQ/dMd2XsmITRo/s1600/challenge7-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="142" src="http://lh6.ggpht.com/_BaefoYBtOwQ/S59zDsyIwPI/AAAAAAAAAXQ/dMd2XsmITRo/s400/challenge7-4.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References&lt;/b&gt;&lt;br /&gt;- SSL/TLS:&amp;nbsp;http://en.wikipedia.org/wiki/Transport_Layer_Security&lt;br /&gt;- RSA:&amp;nbsp;http://en.wikipedia.org/wiki/RSA&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-4186880956650713744?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/4186880956650713744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2010/03/codegate-2010-ctf-challenge-7-weak-ssl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/4186880956650713744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/4186880956650713744'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2010/03/codegate-2010-ctf-challenge-7-weak-ssl.html' title='CodeGate 2010 CTF - Challenge 7: Weak SSL Cracking'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_BaefoYBtOwQ/S59Mv6OohsI/AAAAAAAAAW4/z7INUja_DtE/s72-c/challenge7-1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-3373225370466433282</id><published>2010-03-08T13:32:00.002+07:00</published><updated>2010-03-09T21:11:16.112+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='life'/><title type='text'>Steve Jobs' 2005 Stanford Commencement Address</title><content type='html'>&lt;object height="385" width="480"&gt;&lt;param name="movie" value="http://www.youtube.com/v/UF8uR6Z6KLc&amp;hl=en_US&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/UF8uR6Z6KLc&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;Such an inspiring speech, isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-3373225370466433282?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/3373225370466433282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2010/03/steve-jobs-2005-stanford-commencement.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3373225370466433282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3373225370466433282'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2010/03/steve-jobs-2005-stanford-commencement.html' title='Steve Jobs&apos; 2005 Stanford Commencement Address'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-3125504969125939399</id><published>2009-12-14T01:12:00.037+07:00</published><updated>2009-12-29T14:22:02.745+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='distributed computing'/><category scheme='http://www.blogger.com/atom/ns#' term='barcamp'/><category scheme='http://www.blogger.com/atom/ns#' term='hadoop'/><title type='text'>The Family of Hadoop @ Barcamp Saigon 2009</title><content type='html'>&lt;div id="__ss_2709733" style="text-align: left;"&gt;&lt;object height="355" style="margin: 0px;"&gt;     &lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=hadoop-091213113721-phpapp01&amp;stripped_title=the-family-of-hadoop" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=hadoop-091213113721-phpapp01&amp;stripped_title=the-family-of-hadoop" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="355"&gt;&lt;/embed&gt;    &lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Đây là nội dung phần trình bày của tôi tại &lt;a href="http://barcampsaigon.org/"&gt;Barcamp Saigon '09&lt;/a&gt;. Đúng như tôi dự đoán, số lượng người đến nghe buổi trình bày không nhiều lắm. Điều này cũng đơn giản bởi vì nội dung của đề tài còn khá xa lạ với rất nhiều người. Có lẽ đúng như một bạn đã nhận xét, đây là thứ thuộc loại "hạng nặng". Nếu bạn là một developer thông thường hay là một người không làm việc với các hệ thống phân bố, thì bạn cũng không cần quan tâm đến vấn đề này làm gì.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Và một điều rất may mắn đối với tôi là những người tham dự buổi trình bày là những người thật sự quan tâm. Họ là những người đã, đang và sẽ triển khai những hệ thống có khối lượng dữ liệu cực lớn. Đây là một vấn đề mà còn ít người quan tâm, tại vì thật sự ở Việt Nam số lượng các hệ thống như vậy chỉ chiếm một phần thiểu số. Nhưng những vấn đề như thế này lại là một phần quan trọng của những hệ thống lớn. Chúng tôi đã có một ngày thảo luận thật sôi nổi. Mọi người đã thảo luận từ trong phòng ra ngoài hành lang, từ sáng đến chiều và kết quả là trong buổi chiều phải có thêm một session để mọi người thảo luận về vấn đề này nữa. Chúng tôi được trao đổi về những vấn đề rất thực tế của các anh đến từ Zing, hay những kinh nghiệm đã triển khai của các bạn đến từ Dirox và những bạn khác. Tôi đã học hỏi thêm được rất nhiều kinh nghiệm từ các vấn đề được thảo luận này. Xin cám ơn mọi người đã nhiệt tình tham gia.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Một lần nữa cũng xin chân thành cám ơn những người tổ chức của Barcamp Saigon. Các bạn đã đem đến cho chúng tôi, những người đam mê công nghệ, một ngày thật là tuyệt vời. Chúng tôi đã có cơ hội rất tốt để gặp gỡ, trao đổi và học hỏi lẫn nhau. Tôi đã học hỏi được rất nhiều khi tham gia sự kiện này. Xin hẹn gặp lại mọi người vào Barcamp Saigon năm sau.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-3125504969125939399?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/3125504969125939399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2009/12/family-of-hadoop-barcamp-saigon-2009.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3125504969125939399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3125504969125939399'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2009/12/family-of-hadoop-barcamp-saigon-2009.html' title='The Family of Hadoop @ Barcamp Saigon 2009'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-8105776709553752146</id><published>2009-11-27T23:25:00.001+07:00</published><updated>2011-05-03T17:02:37.733+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sandbox'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='cloud computing'/><title type='text'>Python sandbox</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;a href="http://1.bp.blogspot.com/_BaefoYBtOwQ/SxPixXZuJqI/AAAAAAAAAJE/hvD4alrZAVk/s1600/sandbox.jpg" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5409916915125462690" src="http://1.bp.blogspot.com/_BaefoYBtOwQ/SxPixXZuJqI/AAAAAAAAAJE/hvD4alrZAVk/s320/sandbox.jpg" style="cursor: pointer; display: block; height: 320px; margin: 0px auto 10px; text-align: center; width: 320px;" /&gt;&lt;/a&gt;Gần đây trong giới công nghệ, mọi người đang bàn tán rất nhiều về "điện toán đám mây" (cloud computing). Một trong những dạng cloud computing phổ biến là PaaS (Platform as a Service). Nếu ai quan tâm thì cũng đều biết một ví dụ điển hình của PaaS là Google App Engine (GAE). GAE là một nền tảng cho phép bạn phát triển các ứng dụng web và triển khai chúng trên cơ sở hạ tầng của Google. Hiện nay GAE đang hỗ trợ các ứng dụng web viết bằng Python và Java. Bạn có thể viết ứng dụng bằng một trong hai ngôn ngữ này theo các API mà Google cung cấp, còn việc hosting nó thế nào, scaling nó ra sao thì Google sẽ làm giúp bạn.&lt;br /&gt;Đối với những nhà cung cấp dịch vụ như thế này, một trong những vấn đề được đặt ra là: bạn cho phép ứng dụng của người khác được thực thi trên hệ thống của bạn, vậy bạn phải làm gì để cho ứng dụng đó có thể thực thi tốt nhưng không làm nguy hại đến hệ thống của bạn? Đây là vấn đề cơ bản cần phải giải quyết đối với những nhà cung cấp PaaS. Để giải quyết vấn đề này, người ta thường xây dựng một môi trường để cho ứng dụng có thể thực thi được nhưng không thể làm nguy hại đến hệ thống đang chạy. Môi trường này thường được gọi là sandbox. Bài viết này sẽ giới thiệu một cách để xây dựng một sandbox để thực thi các ứng dụng viết bằng Python.&lt;/div&gt;Trước khi đi vào chi tiết, tôi xin nhắc lại một chút về Python.&lt;br /&gt;&lt;span style="font-size: 100%; font-weight: bold;"&gt;Sơ lược về Python&lt;/span&gt;&lt;blockquote&gt;Python is a programming language that lets you work more quickly and integrate your systems more effectively. You can learn to use Python and see almost immediate gains in productivity and lower maintenance costs.(http://www.python.org/)&lt;/blockquote&gt;&lt;div style="text-align: justify;"&gt;Hiện tại Python có nhiều hiện thực, trong đó phổ biến nhất là &lt;a href="http://www.python.org/"&gt;CPython&lt;/a&gt;. Ngoài ra còn có &lt;a href="http://jython.org/"&gt;Jython&lt;/a&gt;, &lt;a href="http://ironpython.codeplex.com/"&gt;IronPython&lt;/a&gt; và &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/"&gt;PyPy&lt;/a&gt;. Bài viết này sẽ tập trung chủ yếu vào CPython.&lt;br /&gt;Python cũng giống như các ngôn ngữ lập trình khác, thành phần cơ bản nhất của nó là các cú pháp và ngữ nghĩa. Ngoài ra, để cho phép người dùng có thể viết ứng dụng bằng ngôn ngữ này, những người hiện thực của ngôn ngữ còn cung cấp thêm một bộ thư viện chuẩn (standard library).&lt;/div&gt;&lt;br /&gt;Trong CPython, bộ thư viện chuẩn này bao gồm:&lt;br /&gt;&lt;ul&gt;&lt;li style="text-align: justify;"&gt;các &lt;span style="font-weight: bold;"&gt;built-in module&lt;/span&gt; (được viết bằng C) cung cấp các chức năng thuộc về hệ thống như là nhập/xuất file&lt;/li&gt;&lt;li style="text-align: justify;"&gt;các module được viết bằng Python cung cấp những giải pháp được chuẩn hóa cho những vấn đề thường gặp trong việc lập trình ứng dụng.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Các built-in module được nạp tự động vào mỗi khi ứng dụng được chạy cho nên người dùng có thể sử dụng mà không cần quan tâm đến nó. Còn đối với các module khác, ta phải import chúng trước khi sử dụng.&lt;br /&gt;Ta có thể xem thông tin của các built-in module trong biến toàn cục &lt;span style="color: #000066; font-family: 'courier new'; font-weight: bold;"&gt;__builtins__&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;và thông tin của các module đã được nạp trong biến &lt;span style="color: #000066; font-family: 'courier new'; font-weight: bold;"&gt;sys.modules&lt;/span&gt;.&lt;/div&gt;&lt;pre class="python" name="code"&gt;$ python&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dir()&lt;br /&gt;['__builtins__', '__doc__', '__name__', '__package__']&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; dir(__builtins__)&lt;br /&gt;[ ..., '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs', 'all', 'any', 'apply', 'basestring', 'bin', 'bool', 'buffer', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod', 'cmp', 'coerce', ...]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; import sys&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; sys.modules&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;Có thể tham khảo thêm về standard library của Python tại &lt;a href="http://docs.python.org/library/"&gt;đây&lt;/a&gt;.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Các chức năng cần phải hạn chế&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; trong Python sandbox&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Khi bạn cung cấp một platform cho người khác và cho phép ứng dụng của người khác chạy ứng dụng của họ trên hệ thống của bạn, bạn phải tìm cách hạn chế các ứng dụng này thực hiện các chức năng không được phép. Một số chức năng cần phải được hạn chế như:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Các chức năng liên quan đến file như đọc, ghi, xóa file.&lt;/li&gt;&lt;li&gt;Các chức năng liên quan đến process như tạo, hủy process&lt;/li&gt;&lt;li&gt;Các chức năng liên quan đến network như đóng/mở socket&lt;/li&gt;&lt;li&gt;....&lt;/li&gt;&lt;/ul&gt;Ví dụ, ứng dụng của người dùng có đoạn code sau:&lt;pre name="code" class="python"&gt;##### clientcode.py&lt;br /&gt;import os&lt;br /&gt;os.system('ps -ef')&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Đoạn code trên sẽ thực thi lệnh '&lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;ps -ef&lt;/span&gt;' để liệt kê tất cả các process đang chạy trên hệ thống của bạn. Rõ ràng đây là một đoạn code nguy hiểm. Vậy ta phải làm cách nào để hạn chế việc thực thi của đoạn code này?&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Hạn chế các hàm nguy hiểm trong Python&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Thông thường, nếu phía server thực hiện import module trên vào để xử lý thì đoạn code trên sẽ được chạy. Đoạn code này thực hiện 2 việc:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Import module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; của standard library&lt;/li&gt;&lt;li&gt;Gọi hàm &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;system&lt;/span&gt; của module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; vừa import.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Rõ ràng việc để cho người dùng có thể sử dụng được module liên quan đến hệ thống như &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; là một việc nguy hiểm. Do đó, để bảo đảm an toàn cho hệ thống, ta phải hạn chế việc sử dụng các module như thế này. Vậy ta phải làm thế nào để hạn chế chúng? Vấn đề này đã được các nhà phát triển Python đặt ra từ rất lâu và đã được miêu tả trong &lt;a href="http://www.python.org/dev/peps/pep-0302/"&gt;PEP 302: New Import Hooks&lt;/a&gt;.&lt;br /&gt;Nói chung, để hạn chế người dùng sử dụng các hàm nguy hiểm, ta cần phải xây dựng một "import hook" để can thiệp vào các hàm import của người dùng.&lt;br /&gt;Ví dụ, để hạn chế người dùng gọi hàm &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os.system()&lt;/span&gt; ở trên, ta có thể làm như sau:&lt;pre name="code" class="python"&gt;### servercode.py&lt;br /&gt;import sys, imp&lt;br /&gt;&lt;br /&gt;class SimpleImportHook:&lt;br /&gt;   def find_module(self, fullname, path=None):&lt;br /&gt;      if fullname == 'os':&lt;br /&gt;         return self&lt;br /&gt;      return None&lt;br /&gt;&lt;br /&gt;   def load_module(self, fullname):&lt;br /&gt;      module = imp.new_module(fullname)&lt;br /&gt;      module.__name__ = fullname&lt;br /&gt;      module.__loader__ = self&lt;br /&gt;      return module&lt;br /&gt;&lt;br /&gt;hook = SimpleImportHook() &lt;br /&gt;sys.meta_path = [hook]&lt;br /&gt;del sys.modules['os']&lt;br /&gt;import clientcode&lt;br /&gt;&lt;/pre&gt;Khi đoạn code trên được thực thi, chương trình sẽ báo lỗi dạng như sau:&lt;pre name="code" class="python"&gt;Traceback (most recent call last):&lt;br /&gt;...&lt;br /&gt;    import clientcode&lt;br /&gt;...&lt;br /&gt;    os.system('ps -ef')&lt;br /&gt;AttributeError: 'module' object has no attribute 'system'&lt;br /&gt;&lt;/pre&gt;Lỗi này xảy ra do module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; không có hàm &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;system&lt;/span&gt;. Trong file servercode.py ở trên, ta đã hook vào hàm '&lt;span style="font-family: 'courier new';"&gt;import os&lt;/span&gt;' của clientcode. Ta trả về module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; là module rỗng (không có hàm nào trong đó).&lt;br /&gt;Với cách hiện thực này, nó gây ra một số bất tiện. Ví dụ như trong module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; có một số hàm không nguy hiểm và cần thiết cho người dùng như sau:&lt;pre name="code" class="python"&gt;##### clientcode.py&lt;br /&gt;import os&lt;br /&gt;print 'os.name = %s' % os.name&lt;br /&gt;os.system('ps -ef')&lt;br /&gt;&lt;/pre&gt;Nếu chạy lại servercode.py, ta sẽ thu được lỗi như sau:&lt;pre name="code" class="python"&gt;Traceback (most recent call last):&lt;br /&gt;.....&lt;br /&gt;    import clientcode&lt;br /&gt;.....&lt;br /&gt;    print 'os.name = %s' % os.name&lt;br /&gt;AttributeError: 'module' object has no attribute 'name'&lt;br /&gt;&lt;/pre&gt;Lỗi này là do module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; không có attribute nào tên '&lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;name&lt;/span&gt;'. Để giải quyết vấn đề này, ta hiện thực lại import hook như sau:&lt;pre name="code" class="python"&gt;##### servercode.py&lt;br /&gt;import sys, imp, os&lt;br /&gt;&lt;br /&gt;class SimpleImportHook:&lt;br /&gt;   def __init__(self):&lt;br /&gt;      self._os = os&lt;br /&gt;&lt;br /&gt;   def find_module(self, fullname, path=None):&lt;br /&gt;      if fullname == 'os':&lt;br /&gt;         return self&lt;br /&gt;      return None&lt;br /&gt;&lt;br /&gt;   def load_module(self, fullname):&lt;br /&gt;      module = imp.new_module(fullname)&lt;br /&gt;      module.__name__ = fullname&lt;br /&gt;      module.__loader__ = self&lt;br /&gt;      for (key,value) in self._os.__dict__.items():&lt;br /&gt;         if key != 'system':&lt;br /&gt;            module.__dict__[key] = value&lt;br /&gt;      return module&lt;br /&gt;&lt;br /&gt;hook = SimpleImportHook() &lt;br /&gt;sys.meta_path = [hook]&lt;br /&gt;del sys.modules['os']&lt;br /&gt;import clientcode&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Khi chạy lại chương trình, ta có kết quả như sau:&lt;/div&gt;&lt;pre name="code" class="python"&gt;os.name = posix&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;.....&lt;br /&gt;    import clientcode&lt;br /&gt;.....&lt;br /&gt;    os.system('ps -ef')&lt;br /&gt;AttributeError: 'module' object has no attribute 'system'&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Điều này có nghĩa là module &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;os&lt;/span&gt; đã có attribute tên '&lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;name&lt;/span&gt;' và hàm &lt;span style="font-family: 'courier new'; font-weight: bold;"&gt;system()&lt;/span&gt; đã bị hạn chế.&lt;/div&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Lời bàn&lt;/span&gt;&lt;br /&gt;- Để hiểu thêm về Python Import Hooks, có thể tham khảo thêm tài liệu &lt;a href="http://www.python.org/dev/peps/pep-0302/"&gt;PEP 302: New Import Hooks&lt;/a&gt;.&lt;br /&gt;- Bài viết này chỉ nói về một số ý tưởng đơn giản, còn về việc hiện thực Python sandbox trên thực tế sẽ phức tạp hơn rất nhiều.&lt;br /&gt;- Google App Engine cũng dựa vào đặc tả PEP 302 này để hiện thực Python sandbox của họ. Có thể tham khảo cách hiện thực của Google App Engine trong source code &lt;a href="http://code.google.com/appengine/downloads.html"&gt;Python SDK&lt;/a&gt; của họ.&lt;br /&gt;- Ngoài cách hiện thực này, cũng có một số cách khác để hiện thực Python sandbox. ví dụ như cách làm dựa trên &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/"&gt;PyPy&lt;/a&gt;: &lt;a href="http://us.pycon.org/media/2009/talkdata/PyCon2009/027/sandbox.pdf"&gt;http://us.pycon.org/media/2009/talkdata/PyCon2009/027/sandbox.pdf&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-8105776709553752146?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/8105776709553752146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2009/11/python-sandbox.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/8105776709553752146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/8105776709553752146'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2009/11/python-sandbox.html' title='Python sandbox'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_BaefoYBtOwQ/SxPixXZuJqI/AAAAAAAAAJE/hvD4alrZAVk/s72-c/sandbox.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5896983951610053372.post-3719811764111222110</id><published>2009-11-16T00:17:00.000+07:00</published><updated>2009-12-11T19:15:05.442+07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='life'/><title type='text'>Hello World!</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_BaefoYBtOwQ/Snf0NtkwEMI/AAAAAAAAAGs/E5aAVcpawpI/s320/Gazelle.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 214px;" src="http://4.bp.blogspot.com/_BaefoYBtOwQ/Snf0NtkwEMI/AAAAAAAAAGs/E5aAVcpawpI/s320/Gazelle.jpg" alt="" border="0" /&gt;&lt;/a&gt;Every morning in Africa, a gazelle wakes up.&lt;br /&gt;It knows it must run faster than the fastest lion,&lt;br /&gt;...or it will be killed.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_BaefoYBtOwQ/Snf1ExQ27TI/AAAAAAAAAG0/EpzK9Q4aUSo/s320/lion.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_BaefoYBtOwQ/Snf1ExQ27TI/AAAAAAAAAG0/EpzK9Q4aUSo/s320/lion.jpg" alt="" border="0" /&gt;&lt;/a&gt;Every morning a lion wakes up.&lt;br /&gt;It knows it must outrun the slowest gazelle,&lt;br /&gt;...or it will starve to death.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_BaefoYBtOwQ/Snf12yUkBLI/AAAAAAAAAG8/-HcES59P1MU/s320/running.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_BaefoYBtOwQ/Snf12yUkBLI/AAAAAAAAAG8/-HcES59P1MU/s320/running.jpg" alt="" border="0" /&gt;&lt;/a&gt;It doesn't matter whether you are a lion or a gazelle.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;When the sun comes up, you better start running&lt;/span&gt;.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;(The World is Flat - Thomas L. Friedman)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5896983951610053372-3719811764111222110?l=namnham.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://namnham.blogspot.com/feeds/3719811764111222110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://namnham.blogspot.com/2009/11/hello-world.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3719811764111222110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5896983951610053372/posts/default/3719811764111222110'/><link rel='alternate' type='text/html' href='http://namnham.blogspot.com/2009/11/hello-world.html' title='Hello World!'/><author><name>Nham Xuan Nam</name><uri>http://www.blogger.com/profile/04219520862806822348</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='21' src='http://1.bp.blogspot.com/-u1L93ZO5cRc/Tb-6-hdB72I/AAAAAAAAAa4/kiThQhhzbLs/s220/219250_206918486009382_126633947371170_646125_449301_o.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_BaefoYBtOwQ/Snf0NtkwEMI/AAAAAAAAAGs/E5aAVcpawpI/s72-c/Gazelle.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
