qdoan95

Bug this, bug that #6

Tl;dr: from recon to RCE.


Hello, long time no see.

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:
  • phpfm.png, có vẻ như là một screenshot:

Với chừng này thông tin, mình đi search trên Google, và tìm thấy một repository trên GitHub, nhìn rất tiềm năng: https://github.com/alexantr/filemanager/:

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.

Stay safe and happy hacking!

Bug this, bug that #5

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.

Happy hacking!

Code bẩn #1

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:

import requests

url = 'https://api.github.com/search/code?q="%s"'
header = {'Authorization': 'token github-personal-access-token'}
r = requests.get(url % keyword, headers=header)

Ở response sẽ có rất nhiều thông tin, tuy nhiên mình chỉ cần đếm số lần xuất hiện của keyword, nên chỉ cần quan tâm field total_count.

print(r.json()['total_count'])

Phần database mình dùng thư viện mysql.connector, code kiểu như:

mydb = mysql.connector.connect(
  host='localhost',
  user='',
  password='',
  database='githubmonitor'
)

Phần send notification mình chọn Telegram, tham khảo thêm cách tạo bot tại đây. Code khá đơn giản, à mà lấy trên Google thì lại chả dễ =]]

def telegram_bot_sendtext(bot_message):
    bot_token = ''
    bot_chatID = ''
    send_text = 'https://api.telegram.org/bot' + bot_token + '/sendMessage?chat_id=' + bot_chatID + '&parse_mode=Markdown&text=' + bot_message
    response = requests.get(send_text)

    return response.json()

Đế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.

Full script: here. Good luck =]]]]


Như thường lệ, nếu bạn cảm thấy bài viết có ích thì có thể giúp mình duy trì VPS thông qua PayPal hoặc MoMo, cám ơn các bạn rất nhiều!

Happy hacking!

Bug this, bug that #4

Tl;dr: Abuse a feature to achieve Root Command Injection. Original report: https://whitehub.net/submissions/2039.


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à Click to Donate (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 🙏

Happy hacking!

Bug this, bug that #3

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 Click to Donate (qua PayPal) hoặc MoMo. Cám ơn các bạn rất nhiều!

Happy hacking!

Bug this, bug that #2

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 Click to Donate mời mình một ly cafe nhé =]]]]

Happy hacking!

Bug this, bug that #1

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/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. :'(

Ai cũng có lúc mắc sai lầm #1

Để blog lâu quá không có bài mới, thấy cũng kì kì. Thôi nay đang rảnh, cố viết lại một bài ngắn ngắn vậy :))

Gần đây mình không viết được gì nhiều, chủ yếu là do công việc của mình không còn liên quan quá nhiều đến việc tìm lỗi bảo mật trong ứng dụng web như trước nữa. Thay vào đó, mình học lại lập trình, tập code bằng nhiều ngôn ngữ khác nhau (trước đây biết code mỗi Python). Cái gì cũng có cái vui, cái lợi và cái “chưa lợi” của nó. Code nhiều thì lên tay, nhưng phải hi sinh việc update kiến thức mới, lỗi mới, mà không update mấy cái đó thì rõ ràng là không chạy đua công nghệ được với các idol rồi :)) nên là mấy idol có nghía qua bài này hay blog này thì cũng đừng chửi “trình kém mà cứ thích viết tào lao” nhé :))

Đi code mới nhận thấy rằng đôi khi để “xúc” được một hệ thống, một ứng dụng chẳng cần những kỹ thuật gì cao siêu, lắm lúc chỉ cần một sai sót nhỏ xíu là đủ để “lên đường”.

Một trong những sai lầm mà mình thấy rất thường xuyên đó là dev đem source code lên GitHub nhưng để public, ai cũng đọc được. Thường thường mấy pha như vậy chẳng cần đọc code, cứ kiếm file config hoặc mấy file dump sql mà đọc, thế nào cũng có username và password xịn, cầm login thôi, đọc code chi cho mệt.

Một lỗi nữa cũng hay gặp, là dev “tiện tay” bỏ luôn tài liệu hướng dẫn sử dụng hệ thống lên GitHub luôn. Mà file hướng dẫn sử dụng thì thế nào cũng có link demo, username và password sẵn trong file. Có hướng dẫn thì cứ vậy mà dùng thôi, ngại quá :))

Cũng có trường hợp sau khi ngó nghiêng thử code thì nhận ra code có bug :)) SQLi đồ thì hiếm gặp, chứ mấy thể loại như này thì nhiều lắm:

...
$file = $_GET['file'];
$alias = $_GET["alias"];
require "home/controllers/$file.php";
...

Case này thực ra mình không biết cách nào đọc được /etc/passwd blahblah, nhưng, lại là may mắn, mình biết chỗ để đọc được “hướng dẫn sử dụng” =]]

Search những thông tin nhạy cảm này trên GitHub cũng không có gì là khó. Quan trọng là tìm đúng pattern để search, ví dụ đơn giản như “tên tổ chức” + “password”, “tên tổ chức” + “https”,… Nói gì thì nói, human mistake vẫn là cái khó phòng tránh nhất, vì ai mà chẳng mắc lỗi 😀

P/s: Khi mình viết bài này thì Github đã cho dùng private repository free rồi (cho cả team). GitHub cũng có thuật toán để cảnh báo người dùng khi trong source code có chứa những thông tin nhạy cảm luôn. Mong là developers nên tận dụng, lỡ có đưa source code lên thì nhớ để private repository, vậy là đủ, dư sức bảo vệ source code mình khỏi bị nhòm ngó bởi những vị khách không mời 😀

Happy coding, happy hacking!

Cú lừa

Cuộc sống đâu lường trước điều gì… Lại tiếp tục chuỗi ngày ngồi cafe tìm bug dạo thôi các bạn ạ… Bug càng ngày càng khó kiếm, cuộc sống thì khó khăn, ngày xưa còn uống cafe size lớn giờ chuyển xuống uống size vừa… hic…

Hôm trước vừa giới thiệu case exposed folder /.git/, dẫn đến việc lộ source code (bạn nào chưa đọc thì có thể đọc ở đây) xong, thì sau đó một thời gian ngắn, mình lại gặp lại một case tương tự. Tuy nhiên, lần này hơi khác, khi mình check đến folder /.git/ của website thì thấy status code 403 – Forbidden.

Kiểu này là có thanh niên nào nhanh tay report mất rồi. Thường thì “gặp 403 ta cho qua”, tuy nhiên trong trường hợp này thì không nên. Bởi vì rất nhiều sysadmin không biết fix lỗi này hoặc fix không triệt để, dẫn đến việc mặc dù bị forbidden nhưng mình vẫn có thể khai thác bằng cách truy cập thẳng vào /index hoặc /config như hình:

Đọc được file index có nghĩa là mình hoàn toàn có thể đọc được source code, đơn giản chỉ cần ném vào gitdumper.

Trường hợp ngon lành, download được source về thì kiếm file nào có sensitive information mà đọc thôi, ví dụ như:

Leak được info này thực ra cũng không làm được gì nhiều, vì IP internal…

Nhưng mà cuộc đời đâu phải chỉ toàn màu hồng… Có những trường hợp không download được, có thể là do folder /.git/ này đã cũ, có download về được thì cũng chỉ được vài file code cũ hoặc file rác. À nói rác vậy thôi chứ cũng không đến nỗi rác lắm… mấy ông sysadmin hay có kiểu fix thôi chứ không đổi password đâu, biết đâu còn ăn may được…

Nhìn cái kiểu đặt password kia thì khả năng cao là password này dùng chung rồi. Cầm đi login thử, không ngờ vào được admin thật…

Mà với WordPress, đã vào được admin thì nghĩa là đã có RCE…

Thật không may, dưới quyền nginx không chỉ có mỗi WordPress mà còn chạy nhiều thứ khác với kha khá critical info… ls một cái rồi viết report cho nhanh, mất công lại duplicate thì khổ.

Hihi, nói RCE nghe đao to búa lớn vậy thôi chứ thực ra root cause vẫn chỉ là weak/reused password. Mà kệ chứ, cứ có bug là đời đỡ buồn hơn một tí rồi. Mai mạnh dạn gọi ly cafe size lớn, happy hacking!

Lạy ông tôi ở bụi này

Mấy hôm nay rảnh rỗi, lại đang bế tắc với mấy program có offer bounty, nên thôi mình nghỉ xả hơi bằng cách chuyển qua tìm bug ở các VDP – Vulnerability Disclosure Program, đúng chuẩn report vì cộng đồng.

Những program VDP thì thường scope không giới hạn, nghĩa là thoải mái tìm subdomain của *.vdp-program.com. Ném vào tool findomain đã giới thiệu từ những post đầu tiên (à nó vừa update version mới thì phải), mình có một danh sách các subdomain. Lần lượt thử các subdomain đã tìm được thì mình tìm thấy một site X.

View-source site X thì thấy có một file js. Haizz, đã lười rồi còn bắt đọc source js, lại còn pack lung tung :'(

Thôi lỡ rồi, Command + F tìm vài keyword như https://, api/, url:,… cho vui, biết đâu có gì hay :no-hope:

Tìm một lúc thì mình thấy có khoảng 3-4 link gọi API, thử truy cập vào một link thì thật bất ngờ…

Ôi lộ cả email/password ra thế này thì… Ơ mà password nhìn thế kia thì kiểu gì cũng encrypted rồi, làm ăn gì được đâu. Đem đi login thử thì y như rằng, tạch. Dễ ăn vậy thì chơi làm gì nữa.

Đến lúc này thì mình nghĩ ra hai cách tấn công. Cách thứ nhất, có salt và password encrypted kia rồi, nhìn thì có vẻ là dùng AES, giờ bằng cách nào đó, có thể là dùng sai crypto, hoặc key yếu,… tìm ra được key rồi decrypt cái password kia ra là xong. Cách này lúc đầu mới nghe thì có vẻ hay, nhưng thực tế… không khả thi. Cách thứ hai là… vứt nó đi, tìm đường khác dễ hơn =]]]]

Tiếp tục thử thêm mấy link gọi API còn lại, lần này thì có vẻ hay ho hơn:

Không hiểu nổi mấy anh dev, mắc cái gì mà để cái resetPasswordToken ở đó không biết nữa, đã vậy lại còn account admin… Phần việc còn lại bây giờ là đi tìm cái link reset password rồi dùng cái token này quất thôi.

Đến đây lại có ba cách tiếp cận. Một là register một cái account, rồi reset password để gởi link về email của mình, thay token bằng token admin. Tuy nhiên tìm mãi mà không thấy nút Register/Sign up ở đâu cả :'( chắc là hệ thống nội bộ nên không cho đăng ký. Hai là fuzz cái URL reset password. Ba là tiếp tục đọc source js để tìm cái link, hoặc ít ra là cái cấu trúc của link reset password. Lỡ đi đường khó rồi thì thôi, chơi tới, mình chọn cách thứ ba. Đọc code một lúc thì thấy code đoạn reset password như thế này:

Ok, đã đầy đủ mọi thông tin cần thiết. Tóm lại, bây giờ những gì cần làm để takeover account admin là:

  • Vào link login, click vào reset password, nhập vào email admin.
  • Check link gọi API lúc nãy để lấy resetPasswordToken của admin.
  • Thực hiện request dưới đây để đổi password:
  • Login vào confirm.

  • Submit report, và không quên trân trọng cám ơn các anh developer đã tài trợ bug này =]]]]

Happy hacking!