Trước giờ tất cả những lần mình đi phỏng vấn (ở cả 2 đầu bàn) thì đều hỏi/được hỏi những câu hỏi liên quan đến JWT, và trong tất cả những lần đó thì “alg=none” luôn luôn là đáp án đầu tiên. Nhưng hôm rồi vô tình lượn Twitter mình lại thấy có một câu hỏi khá hay:
Rõ ràng đây là một câu hỏi rất thực tế, vì thực ra rất hiếm gặp những lỗi “ngớ ngẩn” như vậy, đặc biệt khi bây giờ developers đã sử dụng các library JWT một cách đúng đắn hơn rất nhiều. Tuy nhiên “alg=none” không phải là lỗi duy nhất có thể xảy ra với JWT. RFC 8725 chỉ ra rất nhiều “lỗ hổng” có thể xảy ra khi dùng JWT, và “alg=none” chỉ là một trong số đó. Vậy thì, any chance for you, the penetration testers/the bug bounty hunters, to find these JWT bugs?
Có 02 cases thực tế mình đã gặp trong quá trình đi pentest/bug bounty từ trước đến nay liên quan đến JWT. Case thứ nhất và cũng là case thường gặp nhất liên quan đến JWT là lỗi không verify phần signature. Nghe hơi sai sai nhưng đây là sự thật. Có một thực tế là một trong những library về JWT được sử dụng nhiều nhất cũng đã từng làm developer confuse giữa jwt.decode() và jwt.verify().
Rõ ràng nếu như developer chỉ dùng jwt.decode() thì sẽ xảy ra trường hợp attacker xoá phần signature nhưng vẫn access được API như hình dưới đây:
Lỗi này lúc trước mình thường xuyên gặp phải, bây giờ thì đỡ hơn nhiều rồi, vì các library đã force phải sử dụng jwt.verify(). Nhưng cẩn thận không bao giờ là thừa, hãy luôn check xem chuyện gì sẽ xảy ra nếu ta xoá phần signature của JWT. Còn nếu tiếp cận theo hướng whitebox thì keyword “.decode()” là một keyword rất đáng để thử.
Case thứ hai, hiếm gặp hơn nhưng không phải là không có khả năng gặp. Theo lý thuyết, suggested key size khi dùng algorithm HS256 là 256 bits – 32 bytes. Tuy nhiên như trường hợp dưới đây thì đúng là “rớt lý thuyết rớt cả thực hành”:
Nếu các bạn nghĩ bài viết này có ích thì có thể mời mình một ly cà phê, hoặc tạo thêm động lực viết bài cho mình bằng cách giúp mình duy trì blog qua PayPal hoặc MoMo. Chân thành cám ơn lòng tốt của mọi người.
Tl;dr: Chiếm quyền admin một trang nội bộ của một mạng xã hội bằng social engineering.
Mình là người rất thích đồ công nghệ, máy tính, màn hình, điện thoại,… các thứ. Nhưng mà sau một thời gian “chạy đua” sắm đồ công nghệ, mình nhận ra mình đang làm chuyện vô nghĩa, tốn tiền vô ích. Một cái điện thoại mới, máy tính mới chỉ làm ta vui vài ngày, rồi lại chán. Đồ công nghệ mạnh thật đấy, nhưng đôi lúc nhu cầu ta không đến mức đó, chỉ cần vừa đủ. Nghĩ được như thế rồi nhưng mình vẫn không bỏ thói quen lướt các trang tin công nghệ khoảng 10-15 phút mỗi ngày, lướt không phải để mua mà chỉ để đọc thêm tin tức, biết thêm nay có chip gì, hãng A có công nghệ gì mới, hãng B có tai nghe gì hay,…
Một ngày đẹp trời, vẫn như thói quen đọc tin tức hàng ngày trên một trang mạng xã hội của Việt Nam, mình bắt gặp một video khá thú vị, video giới thiệu một bộ sản phẩm của hãng L, nghe bảo giá lên tới $5000. Mình cũng đang dùng đồ của hãng này, nên click vào xem review. Xem khoảng chừng gần 02 phút thì mình phát hiện một thứ có vẻ hay ho. Đây là screenshot lúc đó:
Tinh ý thì bạn sẽ thấy anh này đang dùng ứng dụng nhắn tin T ở bên trái, và có vẻ anh ấy dùng Saved messages để take note: gửi file, gửi preview, gửi bookmark link…; còn bên phải là một trang web. URL trong thanh chat khá rõ, nên mình pause video lại rồi gõ URL đó thử vào browser. Đây là giao diện trang web sau khi mình gõ vào và nhấn Enter:
Chắc nhiều người cũng đồng ý với mình rằng bất kỳ việc gì, nếu ta làm đủ nhiều thì ta sẽ hình thành được một cái “sense” nhất định. Mình làm trong ngành này cũng được vài năm, bắt đầu từ việc tò mò về password, nên may mắn có “sense” “đánh hơi” được password khá tốt. Mình đoán cái dòng dưới URL là password, khá chắc chắn.
Nhưng để login được thì còn cần email. Đây là lúc social engineering phát huy tác dụng. Mình theo dõi diễn đàn/mạng xã hội này đủ lâu để có thể biết được quy cách đặt email của họ. Thay vì dùng họ tên thì họ dùng nickname, may mắn là mình cũng theo dõi đủ lâu để biết được nickname của một số admin, moderator. “Thử và sai” – may mắn mình đúng ngay lần đầu thử:
Mình có tìm hiểu sơ qua thì biết được ứng dụng Metabase này là một ứng dụng dạng BI (Business Intelligence), cho phép chia sẻ data và analytics trong tổ chức. Người dùng có thể “Ask a question” – Metabase có một thứ gọi là question builder – dựa trên các câu truy vấn dựng sẵn. Hoặc người dùng cũng có thể tự truy vấn SQL bằng SQL editor. Tài khoản mình vào được, may mắn là tài khoản admin, có quyền cao nhất. Từ đó mình có toàn quyền truy vấn vào cơ sở dữ liệu (nội bộ) của diễn đàn/mạng xã hội này.
Để chứng minh impact thì mình có chụp tấm hình này gửi cho admin của diễn đàn:
Sau khi nhận được report nhanh của mình thì admin cũng nhanh chóng đổi password, rà soát lại server, và tất cả những gì mình nhận được sau khi report là một câu cám ơn:
Nói chung thì mình cũng không đòi hỏi gì cả, mình vẫn report từ thiện như vầy rất nhiều lần, có đôi khi lời cám ơn còn không được nhận. Mình tin là ở hiền gặp lành, cứ làm việc tốt, mình thấy vui là được. Hi vọng có bạn đọc nào đọc được bài này, và cũng bắt đầu “report từ thiện” giống mình – nếu có vô tình thấy được lỗi – để giúp thêm được một cá nhân/tổ chức nào đó tự bảo vệ được mình trong cái thế giới internet càng ngày càng loạn lạc này. Nếu có bug bounty program thì tốt, không thì thôi, gửi cho họ một cái email báo lỗi đàng hoàng, chắc họ cũng không bỏ qua.
Nếu các bạn nghĩ bài viết này có ích thì có thể mời mình một ly cà phê, hoặc tạo thêm động lực viết bài cho mình bằng cách giúp mình duy trì blog qua PayPal hoặc MoMo. Chân thành cám ơn lòng tốt của mọi người.
Post gần nhất của mình có mấy bạn vô comment bảo là chia sẻ thêm về skill recon. Thực ra mình không giỏi recon cho lắm, mà nói thẳng ra là chẳng giỏi gì cả. Hên hên tìm được mấy lỗi vớ vẩn, có một bài là search GitHub làm hoài rồi viết blog xạo xạo chơi vậy thôi, chứ biết hack biết recon gì đâu.
Hơi lan man tí, từ lúc chuyển qua “làm” developer, mình biết thêm nhiều thứ mà có lẽ nếu chỉ làm consultant/pentester thì mình khó mà có cơ hội biết được. Ví dụ như việc trên đời này có một thứ gọi là Selenium. Công cụ này thì chắc đa số bạn đọc blog mình đang làm việc trong mảng security không biết, còn các bạn developer/tester thì lại rành. Nhắc đến Selenium là nhắc đến automation, vì thường Selenium được sử dụng để automate các thao tác với trình duyệt, giả lập lại các tương tác trên trình duyệt như một người dùng thực sự, từ open link, input data,…. Thử tưởng tượng nhập tay vài trăm cái account hay mở vài nghìn cái link bằng tay, chắc chẳng ai dám đi làm tester. Thay vì manual như vậy, tester viết test script, có Selenium tương tác với trình duyệt hộ, tiện.
Nhưng mà nói chung là trên đời này tool nào cũng vậy, có xịn đến đâu cũng cần có người vận hành. Muốn Selenium chạy được thì cần test script, test script muốn chạy đúng cần có data, data thì do người viết (tester) cung cấp. Mà đã là con người thì ai cũng có lúc mắc sai lầm. Developer hay tester cũng như nhau, cứ push code lên GitHub mà để public thì cũng có ngày bị xiên.
Tìm những thứ này không khó, quan trọng là tìm đúng keyword. Cứ đè hàm sendKeys() của Selenium và field txtPassword hoặc password mà gõ thì thế nào cũng ra.
Thường thường, đa số những kết quả tìm được không có ý nghĩa gì lắm, tuy nhiên cũng có lần mình vào được một dashboard quản lý SMS brandname.
Cá nhân mình nghĩ mấy thể loại tấn công SMS brandname rồi phishing gì đó coi vậy mà hiệu quả phết, bằng chứng là ngày nào lên Facebook cũng thấy có người bị lừa mất tiền, dù ngày nào cũng thấy mấy ngân hàng nhắn tin cảnh báo lừa đảo.
Một sai lầm phổ biến khác của developer là quên không tắt debug, hoặc không tắt các development tools khi release. Lỗi này tưởng chừng đơn giản, nhưng nhiều khi lại dẫn đến những hệ quả cực kỳ nghiêm trọng. Case dưới đây là một ví dụ. Developer không tắt symfony profiler, một development tool cho phép xem nội dung các request. Chỉ cần thêm /_profiler/ vào sau domain là xong (nhớ add vào wordlist nha =]]):
Tất cả những gì attacker cần làm khi đã đến đây rồi chỉ là… chờ đợi. Như trong hình, request login có status 302 kia khả năng cao sẽ có username và password của user/admin. Click vào token tương ứng với request kia để xem:
Rõ ràng, có username và password từ trên trời rơi xuống thế này thì ngu gì mà không login chứ =]]]]
Hay như trường hợp bật debug này (sẵn thêm luôn /debug/ vô wordlist nữa nha =]]):
Ca này còn nguy hiểm hơn, khi attacker có thể bắt được request có chứa các HTTP headers quan trọng, như Authorization hay Token,… và dùng các thông tin có được để có thể truy cập trái phép vào các tài khoản người dùng khác. Thêm nữa, ứng dụng đang dùng Yii 2 version cũ, nghe đâu là có RCE (link), còn có exploit được không thì mình không biết, hihi.
Mình viết blog cho vui, tuỳ hứng lắm, có hứng thì viết, có bug hay thì viết, không có thì thôi, nên không đảm bảo được tần suất ra bài. Mong bạn đọc thông cảm, và nếu có thể thì tiếp thêm động lực cho mình qua PayPal hoặc MoMo cho mình để tăng tần suất ra bài mới nhé =]]]]
Nếu bạn theo dõi series vớ vẩn này đủ lâu thì sẽ nhận ra cái quy trình tìm bug của mình thường thường là dạo vòng ngoài, tìm các bug unauthenticated (nếu có) trước, sau đó mới đến bước register/login để tìm các bug authenticated. Dễ dàng nhận thấy tìm bug kiểu như vậy thì khả năng thấy bug ngay khá là thấp, nhưng nếu có bug thì có thể sẽ là một bug to. Mình nghĩ đó là một kiểu đánh đổi thôi, mình sẽ không có lợi thế so với các bạn khác, ví dụ các lỗi XSS hay IDOR (broken access control) thì thường thường không đến lượt mình, còn nếu lỡ như có bug gì unauthenticated thì mình hốt ngay được. À mà xác suất để tìm được unauthenticated RCE thì còn thấp hơn nữa, nên đây là một cách tìm lỗi thất bại, hi vọng trong các bạn không có ai học theo mình =]]
Tuy nhiên xác suất thấp không có nghĩa là không thể xảy ra, cuộc sống mà, không nên đánh mất hi vọng. Target lần này là một trang khá cũ, chạy PHP, cũng không có nhiều chức năng. Fuzz nhẹ thì thấy directory listing ở gần như tất cả các directory:
Cái folder filemanager kia có vẻ hay ho, nhảy vào xem thử thì đúng là hay ho thật. Có 2 files đáng lưu ý ở đây:
filemanager.php, file này cần username và password để authentication:
Không cần phải tinh mắt lắm mới có thể nhận ra file phpfm.png trong folder filemanager trên server và screenshot trong repository là hoàn toàn giống nhau. Quay lại đọc code, cũng không khó để tìm thấy default username và password là fm_admin:fm_admin.
Một pha ăn may đỉnh cao khi mình dùng credential này và log in thành công:
Cũng giống như mọi bài toán đều dễ khi ta biết đáp án, lần này mọi chuyện cũng bớt khó khăn hơn rất nhiều khi ta có source code (lại còn không dài, không phức tạp). Theo như source code, để tìm path upload, mình chỉ cần view-source (sau khi đã login thành công):
Đến đây thì thôi coi như xong rồi. Được upload tuỳ ý, lại còn biết path upload, tiếp tục làm đúng theo các bước trong source code từ repository trên GitHub, mình thực hiện tạo folder và upload cái phpinfo() làm PoC lên server thôi:
Thêm một lần nữa ăn may, ai mà có ngờ từ directory listing -> reconnaissance -> default credential -> arbitrary file upload -> RCE được, nhỉ.
Dịch bệnh càng ngày càng phức tạp, không biết đến khi nào mới được trở về cuộc sống bình thường nữa, mọi người cố gắng ở nhà, hạn chế ra ngoài, giữ sức khoẻ nhé. Dịch bệnh ai cũng khó khăn, treo donate tiếp thì cũng kỳ, nên nếu mọi người cảm thấy bài viết của mình có ích thì thay vì donate cho mình, mọi người có thể giúp đỡ cho các hoàn cảnh khác khó khăn hơn quanh khu vực mình đang sống nhé. Cám ơn mọi người nhiều nhiều.
Tl;dr: Dựa vào lỗi misconfiguration từ phía ứng dụng để bypass authentication, từ đó có quyền truy cập vào admin panel của ứng dụng. Đây là phiên bản có nhiều hình ảnh hơn phiên bản đã được disclose trên HackerOne.
Khoảng hơn nửa năm trước mình có tập tành tìm bug trên HackerOne. Một trong những chương trình VDP lớn nhất trên HackerOne là DoD, chương trình của bộ quốc phòng Hoa Kỳ. Thấy họ resolve nhiều bug quá nên mình cũng thử tìm xem thế nào. Scope của DoD là cả một top-level domain, rất lớn. Hình như trong số toàn bộ các tool find subdomain mà mình đang sử dụng không có cái nào support tìm domain và subdomain từ top-level domain, nên đầu tiên mình sẽ đi search Google với dork “site:.tld“, từ đó tìm ra một list các domain, sau đó pick random một domain nào đó rồi thử các bước như vẫn thường làm.
Như thường lệ, việc đầu tiên mình làm là enumerate subdomain. Càng có nhiều subdomain, tỉ lệ có bug càng cao. Có được list subdomain “hợp lệ” thì làm như mọi người vẫn làm, cho qua ffuf với một wordlist mà giang hồ mạng hay dùng. Code thêm một cái script nhỏ nhỏ để in ra title của site, tăng tỉ lệ tìm được low-hanging fruit bug. Siêng nữa thì cho qua eyewitness để có thêm screenshot, thêm info,… hoặc lười quá thì cài Osmedeus cho nó tự làm rồi đợi nhận kết quả thôi. Nếu làm xong hết những bước này mà chưa ra gì hay ho thì thôi, đi ngủ đi chứ làm gì nữa. Trường hợp này của mình là một ví dụ, nó chả ra cho mình một cái info gì thú vị hay hấp dẫn gì cả, ra mỗi cái biển báo như thế này:
Với khả năng ngoại cảm bảo mật của một người chơi hệ tâm linh, mình đem cả cái URL vứt lên GitHub. Như mình vẫn hay đề cập ở các post trước, GitHub là thiên đường của developers, do đó cũng là thiên đường của hackers. Developers có gì cũng vứt lên GitHub, thì hackers cũng vậy, muốn hack gì thì lên GitHub kiếm. Và rõ ràng GitHub không làm mình thất vọng, hai endpoints có vẻ tiềm năng xuất hiện trước mắt mình:
Lần lượt vào thử hai endpoints vừa tìm thấy thì nhận ra SOAP service description đang bật ở endpoint thứ hai, cộng với một keyword tìm được ở endpoint thứ nhất thì có thể khẳng định trên server này đang chạy một online assessment platform.
Lướt một vòng thì mình thấy có hai methods đáng chú ý và có gì đó sai sai:
Method GetAdministratorList sẽ trả về toàn bộ info của các administrators có trong database, còn method GetAccessAdministrator sẽ trả về một URL để login tuy nhiên không cần mật khẩu ?? 😀 ??
Đợi chờ gì nữa, copy request rồi mở Burp lên mà hốt xác nó thôi. Kết quả thì như các bạn có thể thấy ở hình dưới.
Mọi thứ sẽ hoàn hảo nếu như không có cái chỗ trong khung đỏ kia. Mình không có account, cũng chưa từng làm việc với cái service này, thì mấy chỗ “string” kia biết điền gì cho đúng?
Bị lây tính của mấy anh em developers tay to ở chỗ làm, mình chọn cách đi kiếm document đọc, khoảng 10 phút thì thấy có vài điểm có vẻ thú vị ở cơ chế xác thực dùng trong service này:
Với trình tiếng Anh hạn hẹp của mình thì mình hiểu là trong trường hợp này SOAP Trust header có quyền ưu tiên cao nhất, override được cả security SOAP header và basic authentication (nếu basic authentication được enable). Nếu không đưa bất kỳ header nào vào SOAP headers thì sẽ dùng basic authentication. Lưu ý thêm là để bật basic authentication thì Trust require setting phải được tắt và Security require setting phải được bật.
Hmm, vậy sẽ ra sao nếu mình vừa không pass gì vào SOAP header, server lại không bật basic authentication, hoặc bật không thành công? Nếu Trust require setting đã tắt và Security require setting chưa bật thì sẽ dùng method nào? Thử phát, xoá hết mọi thứ trong tag <soap:Header> (Cả tag <Trust> lẫn tag <Security>) xem sao:
Ngon lành. Mình nghiệp dư nên mình phân tích cho dài vậy thôi, chứ gặp mấy hackers có kinh nghiệm, có 6th sense, người ta thấy header thì người ta xoá luôn phát một là thấy hàng về rồi, hơi đâu ngồi giải thích dài dòng như mình. Giờ xài tiếp method GetAccessAdministrator lấy link “đăng nhập không mật khẩu” vào tài khoản administrator thôi.
Có link rồi thì lấy đăng nhập thôi, còn gì nữa đâu…
Nói một cách công bằng thì lỗi này cũng chỉ là một lỗi ăn may 🙂 cũng không có nhiều kỹ thuật gì. Hi vọng là bài viết này của mình giúp được gì cho ai đó :)) Nếu các bạn nghĩ bài viết này có ích thì có thể mời mình một ly cà phê, hoặc tạo thêm động lực viết bài cho mình bằng cách giúp mình duy trì server theo một trong hai cách: qua PayPal hoặc MoMo nhé. Chân thành cám ơn sự ủng hộ của mọi người.
Tl;dr: viết một (quick, dirty and easy) script để tìm kiếm/theo dõi keywords trên GitHub.
Câu chuyện bắt đầu khi mình vô tình tìm được một vài “lỗi” dạng information disclosure trên GitHub của một công ty ở VN. Information disclosure thì cũng có this có that, dăm ba cái full path, version,… thì thôi bỏ đi, chứ những thứ sensitive như là hardcode secret, API keys, authorization token,… thì đáng được đưa vào report. Developers của công ty này, uhm, thường xuyên push code lên GitHub và sẵn tiện thì hay kèm thêm username/password/URL/token… trong repository luôn. Ờ thì, thấy lỗi, tìm cách report, may mắn thì có bounty, không may thì nhận lời cám ơn, không may nữa thì bị bơ luôn, chuyện bình thường. Chuyện sẽ không có gì để nói nếu developers của bên công ty đó không chơi trò mèo vờn chuột với mình: mình phát hiện lỗi, report cho công ty, họ gỡ xuống, vài hôm sau lại thấy ông khác đẩy code khác lên, vẫn có “hàng nóng” kèm theo, lại report. Ban đầu mình tìm thủ công, sau đó thấy bên này lặp đi lặp lại khoảng gần chục lần, nên mình nảy ra ý tưởng là đi tìm tool hoặc viết tool tìm tự động cho nhanh.
Thực ra ý tưởng này hoàn toàn không mới, bằng chứng là khi đi dạo một vòng trên GitHub bạn có thể dễ dàng tìm được những tool/script với công dụng tương tự và hoạt động rất hiệu quả, đã được dùng từ rất lâu rồi, ví dụ như gitleaks,gitGraber,… Chính GitHub cũng đề cập cũng như cảnh báo việc developer ném sensitive information lên GitHub, và cho phép secret scanning đối với cả public lẫn private repository để hạn chế tình trạng trên. Nhưng kết quả thì cũng không khá hơn là bao, đơn giản thôi, vì ai cũng có lúc mắc sai lầm.
Tuy nhiên, có vài điểm trong các tool public này hơi không đúng ý mình lắm, sửa lại thì cũng được nhưng khá mất công, mình thì lười, nên thôi, viết script tìm luôn cho nhanh. Như đã đề cập ở trên, developers có thói quen vứt sensitive information lên GitHub, và trong code push lên thường có mention đến domain, nên mình sẽ thực hiện tìm kiếm chủ động, và theo dõi (monitor) các keyword liên quan đến domain của công ty (target) mình nhắm đến. Không phải lúc nào mình cũng rảnh để vào GitHub search rồi sort theo recently indexed, nên mình code một (quick and dirty) script để làm hộ. Ý tưởng của mình rất đơn giản: tìm kiếm thông tin về domain (keyword) của target bằng cách search trên GitHub, đếm số lần xuất hiện của keyword, lưu vào một database, cho chạy cronjob. Nếu số lần xuất hiện của keyword thay đổi nghĩa là vừa có code mới được push lên, lúc này database sẽ được update số lần xuất hiện của keyword, đồng thời sẽ có thông báo qua Slack/Telegram/Discord,… mình chỉ việc vào check repository mới nhất có chứa keyword bằng link Slack/Telegram/Discord vừa send.
Trong các quảng cáo thường có câu: “Đọc kỹ hướng dẫn sử dụng trước khi dùng”, cá nhân mình thấy câu này xứng đáng 10 điểm. RTFM, ta biết được GitHub có cung cấp Search API đầy đủ và rõ ràng cho chúng ta sử dụng, chỉ cần vào Developer settings tạo cho mình một Personal access token với permission phù hợp. Trường hợp này mình chỉ muốn search theo keyword thì đơn giản chỉ cần dùng:
Đến đây thì phần cắt ghép cũng coi như xong rồi, chỉ cần thêm một chút magic nữa để script hoạt động trơn tru. Tận dụng con VPS $5/tháng sống bằng tiền donate của các bạn để chạy cron, thời gian thì tuỳ các bạn, mình thì chọn 5 phút, máy chạy chứ mình có chạy đâu mà lo. Kết quả sẽ là dạng như thế này:
Script này hoạt động tốt nhất với các trường hợp monitor một hoặc nhiều keyword/domain của một công ty cùng lúc (dạng internal hunting), nếu keyword hoặc domain đó unique nữa thì càng tốt. Ưu điểm (và cũng là nhược điểm) của phương pháp này là bạn chỉ biết được có keyword xuất hiện, còn ở đâu thì bạn phải tự check repository thủ công, do đó rất dễ gặp trường hợp false positive. Với mình thì không vấn đề gì, vì mục đích mình muốn như vậy, còn với các bạn thì tuỳ nhu cầu sử dụng thực tế mà các bạn hoàn toàn có thể phát triển thêm.
Spoiler: Bài này chỉ là bài chia sẻ, không phải bài hướng dẫn. Mình cũng không phải developer cao siêu gì, code nhanh code vội, quan trọng dùng được, nên các siêu nhân nhìn vô code sẽ rất ngứa mắt. Code này có lẽ còn chứa nhiều potential critical security issues. Code bẩn, code bẩn, code bẩn, cái gì quan trọng nhắc ba lần, nên mong các chuyên gia nếu có vô tình ghé mắt qua đây thì bỏ qua cho em, góp ý hoặc donate thì em xin nhận, còn gạch đá thì thôi, em cám ơn nhiều.
Hơn bốn tháng trời không viết nổi một bài, bờ-lốc bờ liếc mốc meo phủ bụi, cũng muốn viết lắm, nhưng mà làm gì có bug đâu mà viết 😭
May sao tháng trước sàn WhiteHub có email thông báo có program mới, cũng không trông mong gì nhiều, vào xem thử cho biết. Lúc nhìn target thú thực mình cũng không muốn làm cho lắm, lý do thì chắc các bạn cũng sẽ hiểu được khi xem hình dưới đây:
Nhưng thôi đang trong giai đoạn khó khăn, 🍚 👕 🌾 💰, kiếm được đồng nào hay đồng nấy, mình thử mở Burp (tất nhiên là Community Edition) lên xem thế nào. Sau khi lướt qua một vòng thì mình thấy có tính năng Add link YouTube, tính năng này mình cũng đã có gặp một vài lần ở những program khác, vì vậy nên không khó lắm để mình tìm được lỗi SSRF ở đây:
Tuy nhiên nếu chỉ dừng lại ở scan internal port và leak service banners thế này thì impact cao nhất có thể chỉ là Medium. Mà nhìn cái “bảng giá” ở trên thì…
Nhìn kỹ hơn một tí, trong response trả về có một điểm hơi lạ, nhìn có vẻ như là một warning/error khi chạy command line vậy. Đi search keyword youtube-dl, biết được đây là một tool cho phép download video từ YouTube từ CLI. Linh tính mách bảo mình: ở đây có bug, rất có thể sẽ inject được gì đó.
Để kiểm chứng, mình thử nhập các ký tự đầu lâu xương cá, đặc biệt là các ký tự như ‘, “, &, |, >, `… vào phía sau http://localhost để xem kết quả trả về là gì. May mắn, không lâu sau thì mình có một kết quả khả quan:
Input: http://localhost'; || `id`'
Output: "/bin/sh: -c: line 0: syntax error near unexpected token `||'\n/bin/sh: -c: line 0: `youtube-dl -J 'http://localhost'; || `id`''\n"
Ngoài lề, chỗ này chắc sẽ có bạn hỏi sao không có hình cho trực quan, cho dễ nhìn, thì xin thưa là do xài Burp Community Edition, không có chức năng save state, nên lỡ tay bấm tắt project là mất luôn, text thì do copy ra để debug nên còn chứ hình thì không kịp chụp 😂 để cố kiếm bug rồi đầu tư bản Pro, mạnh dạn nói “Không” với hàng crack nhé ahihi.
Quay lại chủ đề chính, có error như kia thì khá rõ ràng rồi. Input của mình sẽ được truyền thẳng vào câu lệnh download, mình đoán kiểu có dạng như sau:
`youtube-dl -J '$input'`
Việc của mình bây giờ chỉ là inject payload sao cho đúng chỗ và work 🙂 payload thì đơn giản nhẹ nhàng thôi:
http://localhost'; id; echo '
Chạy command dưới quyền root như này thì thôi, còn gì để nói nữa. Viết nhanh cái report chứ không thì lại là người đến sau mất, dù biết là report nếu viết gấp nó sẽ không ra thể thống gì cả, không được đàng hoàng như trên blog, nhưng thôi kệ, “cuộc đua số” mà, đành chấp nhận. Cũng may trời thương, không duplicate. Team xử lý rất nhanh, chỉ trong khoảng 3 tiếng từ khi mình report là issue đã được triaged, fixed, resolved và bounty rewarded.
Bounty 2 triệu, đóng thuế hết 10% còn 1 triệu 800 nghìn, hơn bốn tháng kiếm được một bug (vừa đúng bằng thời gian giãn cách giữa hai bài #3 và #4). Còn buồn hơn nữa, khi bài viết này được đăng cũng là lúc program tăng giá gạo lên thành 5 triệu cho một lỗi critical 🤦
Quay qua quay lại mất hẳn 3 triệu, đúng thật làm IT giàu, nhưng chắc là giàu tình cảm… tuy nhiên thiết nghĩ tình cảm thì nên được thể hiện đúng chỗ, mà chỗ đúng là (PayPal) hoặc chỗ này (MoMo) nhé các bạn, donate cho mình có tiền trả tiền thuê server với, chân thành ghi ơn 🙏
Tl;dr: chain hai lỗi Information disclosure (Medium-High) để khai thác thành công lỗi Account Takeover (High).
Quay lại thời gian này năm ngoái, khoảng thời gian mà mình chưa đi làm lại sau khi nghỉ việc ở công ty cũ, cũng rảnh rỗi nên tập tành tìm bug. Tình cờ biết được một công ty ở VN có mở một program bug bounty, nên mình cũng “quan hệ cửa sau”, xin mở được một account ở đây để tìm bug cho vui. Lúc được cấp account thì mình cũng có vào nghịch thử, thấy website được code bằng PHP, Laravel, có vẻ là một framework ticket nào đó. Test sơ sơ vài phát thấy chỉ có mấy lỗi info này nọ nên thôi, bỏ qua, tập trung tìm lỗi từ các program có trong platform.
Bẵng đi đến đầu tháng này, sẵn tiện vừa code được một cái tool gom info, mình đem chạy thử với domain của công ty kia (tạm gọi là websitehucau.vn). Và mình phát hiện ra tool của mình có một bug rất nghiêm trọng. Mình check regex không đúng, thay vì trả về các subdomain dạng abc.websitehucau.vn, thì nó lại gom luôn các domain dạng abc-websitehucau.vn, và cả subdomain dạng xyz-abc.websitehucau.vn nữa chứ :facepalm:
Cũng khá tình cờ, khi mình mở lại log debug xem thì bất ngờ thấy có một domain hơi lạ, ss1-abc.websitehucau.vn, trong khi subdomain abc.websitehucau.vn chính là platform bug bounty program đã nói ở trên! Mình chợt nghĩ, nếu nó giống site kia, thì có lẽ nào nó cũng là một version khác, kiểu kiểu staging/dev, hoặc một bản backup? Biết site được code bằng Laravel, thôi chọt thử một cái payload huyền thoại: .env
Không ngờ là site này vẫn còn mắc phải cái lỗi kinh điển và cơ bản như vậy. Trong số những thông tin nhạy cảm này thì mình thấy có credential của email, dùng Zoho mail. Thử login thì vào thành công, có vẻ khá ngon rồi.
Nhìn có vẻ không có gì, tạm bỏ qua. Tiếp tục fuzz thử thì thấy có một file thú vị: adminer.sql
Pha này thì chắc là ông nào backup nhưng quên xóa rồi. Download database về xem thử thì thấy username, email, password,… của mình trong đó, lúc này có thể confirm database này đang được sử dụng (hoặc đã được sử dụng) trong thực tế.
Để chắc chắn hơn, mình login vào trang chính để xem lại list user, nhưng lại quên password. Mình có thử crack password tìm thấy trong db kia thì cũng được vài cái, nhưng tiếc là không crack được password admin cũng như password của mình, nên mình ra homepage bấm “Forgot Password“, điền email của mình vào. Check mail thì thấy mail gửi link reset password nhìn quen quen, nhìn kỹ thì thấy chính là cái mail ban đầu bị leak trong file .env đã nói ở trên. Thế là mình quay lại login vào email kia, xem trong tab “Đã gửi“:
Ok ngon, lúc này thì đã đủ info để chain những bug này lại thành một bug Account Takeover hoàn chỉnh:
Dùng email có được từ file adminer.sql để request password reset.
Login vào mail để lấy token/link reset password của user, rồi change password —> account takeover.
Viết report rồi gửi thôi, cũng không ngờ là từ một bug ngớ ngẩn trong code của mình mà mình có tìm ra được một bug “coi cũng được” như này :))))
Như thường lệ, tiếp sau phần write-up là tiết mục “khều donate” =]]]] nếu bạn cảm thấy bài viết có ích thì có thể mời mình một ly cà phê, hoặc tạo thêm động lực cho mình viết bài bằng cách nhấn vào nút (qua PayPal) hoặc MoMo. Cám ơn các bạn rất nhiều!
Tl;dr: Vô tình tìm được một lỗi có thể làm lộ toàn bộ source code của công ty U, impact tương tự như vụ gần đây nhất của công ty G ở VN. Bug low tech, không chứa quá nhiều hàm lượng kỹ thuật. Nút donate ở cuối bài =]]]]
Chuyện xảy ra vào một buổi chiều đẹp trời, report của mình cho một private program trên HackerOne bị duplicate. Nghĩ cũng đúng, bug dễ tìm quá, low-hanging fruit thì ai cũng tìm được.
Khi khai thác lỗi đó mình có tìm được một token gọi là “gitlab-ci-token“, và có mention trong report. Sau khi report thì mình mới nảy ra ý tưởng: lấy keyword “gitlab-ci-token” này đi search trên GitHub, rất có thể có nhiều công ty/tổ chức/cá nhân cũng đang mắc lỗi này. Nghĩ là làm, mình search ngay, sort theo recently indexed, và nhận được vài kết quả có vẻ khả quan, trong đó có một kết quả là một file json, của một plugin wordpress, thời gian upload lên cũng khá gần. Mình vào thẳng website của plugin đó, tải source về để kiểm tra xem token này là của người dùng upload lên GitHub, hay là của plugin.
Plugin có hai version, free và premium (có trả phí). Mình chọn bản free, được redirect qua trang download plugin. Plugin này nằm trong top popular, với hơn 3 triệu người dùng.
Sorry vì phần censored, lúc đầu mình xin phép được private disclose, che đi thông tin, không ngờ họ hào phóng cho mình full disclose, mà mình lại lỡ che mất rồi.
Sau khi download file zip về, extract ra, mình tìm tới đúng file json đã đề cập ở trên (vendor/composer/installed.json). Vẫn thấy tồn tại token, nghĩa là token này vô tình bị developer plugin cho vào đây, và quên xoá khi release.
“gitlab-ci-token“, như tên gọi, là một job token, được mô tả rõ ràng ở đây. Bản chất nó vẫn là token (khác biệt là job token không có quyền write) nên hoàn toàn có thể được dùng để access vào projects như một personal/projects access token, theo cách được mô tả ở đây.
Rõ ràng token này vẫn còn valid, ai có được token này đều có thể access được vào GitLab nội bộ này. Nguy hiểm hơn, token bị leak ra này gần như có quyền trên toàn bộ các projects trong GitLab. Clone thử một cái về để “chứng minh lỗ hổng”:
Fact: Sau khi screenshot thì folder này đã được xoá ngay.
Đủ để chứng minh lỗ hổng rồi, viết ngay một email report. Xác định là làm từ thiện rồi, vì trên homepage mình không tìm được chỗ nào cho email hay có form contact gì cả. May là trong source code vẫn có email của developer ở phần header. Vài tiếng sau thì nhận được email reply, họ báo là đã up lên version mới, xoá cái token bị leak trong source code, revoke toàn bộ token cũ, và đã audit toàn bộ source code để ngăn tình trạng này xảy ra.
Hôm sau thì họ cho mình lên trang acknowledgements, và đương nhiên rồi, report từ thiện thì làm gì có bounty. Tuy nhiên, nếu có ai đó cảm thấy mình xứng đáng được nhận bounty, hoặc cảm thấy (các) bài viết của mình có ích, đừng ngại nhấn nút mời mình một ly cafe nhé =]]]]
Rảnh ngồi nhìn lại mấy bug ngày xưa kiếm được, thấy toàn là bug… tào lao. Kiểu, mấy bug đó quá đơn giản, chẳng ai thèm tìm, chẳng ai thèm submit thì mình lại đi submit và may mắn được accept, còn lại thì giống như một lời một hoặc nhiều idol nào đó (có thật cũng như tưởng tượng) đã nói: “Bug vậy cũng submit/viết bài, suốt ngày lộ source GitHub, password yếu, đọc report/blog chẳng có tí hàm lượng kỹ thuật nào trong đó”. Chịu, ai nói thì nghe, trình kém mà ¯\_(ツ)_/¯
Điển hình trong số đó là một bug ngày xưa mình tìm được của một website cũng gọi là “có số má” ở VN, tạm gọi là websitehucau.vn đi. Bằng “các biện pháp nghiệp vụ” như search Google, search GitHub, chạy tool có chọn lọc,… mình tìm được một list các subdomain của website hư cấu này. Nhìn sơ qua thì thấy có một subdomain có tên khá lạ: xxx-public-api.websitehucau.vn. Truy cập vào thử thì thấy 404 not found =]]]]
Một lỗi điển hình mà newbie như mình hay gặp, đó là cứ gặp 403 hay 404 là nghỉ, không tìm tiếp nữa. Mãi sau này, cắp sách theo học các idol mới ngộ ra, cứ đi fuzz hết, biết đâu nó chỉ xoá index.html thôi chứ còn vẫn để những file khác 🙂 may mắn, sau khi thử vài lần thì mình tìm ra được swagger docs ở path /swagger/index.html
Cũng không có gì đặc biệt, đa số là những API gọi những thứ đặc thù của website, trừ hai API: /get-all-domain-config và /update-domain-config-by-code. Cái tên nói lên tất cả, mình đoán có lẽ đây là API để xem và chỉnh sửa các config domain gì gì đó. Vào bấm execute xem thử thì thấy kết quả trả về như thế này:
Ờ đúng là xem config, map giữa code và domain của website này rồi.
Ủa mà khoan, mình đâu có đăng nhập hay authorize gì ở đây đâu, sao xem được? Hay cái này không có cơ chế authorization? Confirm lại bằng cURL thử, lỡ đâu còn cookie hay có lỡ nhập key gì vào mà không để ý:
Chính xác là không có authorization. Tới đây thì chắc chắn có vấn đề rồi, mình thử ngay API thứ hai (API update), lấy info từ response ở trên, POST lên xem thử, mạnh dạn nhấn “Execute”, và kết quả:
Bằng request như trên mình có thể update toàn bộ các config domain thành domain của mình. Giờ mà mình đổi toàn bộ domain websitehucau.vn này thành bu.gbounty.cc hay cái gì đó tào lao khác thì chắc là công ty hư cấu này toang toàn tập!
Tới đây thì report thôi, trình cùi, biết làm gì hơn nữa :)) Happy hacking!
P/s: Sau khi report thì bug này được website đó công nhận severity ở mức Critical, và được maximum reward :)) sau đó thì website này dẹp luôn chương trình bug bounty… :'(
P/s 2: Hãy cứ xem website này là một website hư cấu đúng nghĩa đi các bạn, đừng cố đi soi, đi tìm hiểu website này là website nào, của công ty nào abcxyz làm gì, làm như vậy mai mốt mình không được viết blog chia sẻ kiểu này nữa đâu. :'(
Recent Comments