How I bypassed Akamai WAF and exploited SQL Injection
Table of contents
- I. Introduction - What is Bypassing WAF?
- II. The discovery of SQL Injection
- III. Bypassing WAF & Exploitation
- IV. How can this be fixed
- V. Final Thoughts
- I. Giới thiệu – Bypass WAF là gì?
- II. Phát hiện SQL Injection
- III. Vượt WAF & Khai thác
- IV. Làm thế nào để khắc phục?
- V. Lời kết
- References/ Tài liệu tham khảo
In this blog, we will explore the process from the initial SQLi detection to bypassing the WAF, further exploiting the vulnerability, and collecting sensitive data.
I. Introduction - What is Bypassing WAF?
WAF = Web Application Firewall
Bypassing WAF involves finding ways to evade the security mechanisms put in place to protect web applications from malicious attacks.
Different WAFs have distinct features and detection capabilities, the effectiveness of bypass techniques can vary depending on the specific implementation and configuration of each WAF.
There are some common techniques for Bypassing WAFs:
Obfuscation
Encoding
HTTP Parameter Pollution
Manipulating Headers
Payload Fragmentation
Case Variations
...
We can test these techniques and observe the application's responses to understand how it blocks our requests. From there, we can attempt to find a way around these defenses.
The WAF that i will mention in this blog? It’s Akamai.
I knew I was up against it when my SQLi payload was met with a 403 Access Denied page and a Akamai Reference code #18.xx
in the response body.
Simple enough, let’s see a real life example.
II. The discovery of SQL Injection
In a recent security testing engagement, I had the opportunity to participate in testing the website of a well-known retail brand. As always, under the black-box pentest strategy, I started by crawling on all the endpoints on the website. After collecting the necessary endpoints, I proceeded to scan using their provided testing tool and manually test each one.
After the scan is finished, while scrolling through the scanning result of the tool, I found a lot of findings and then this was the one that got my interest.
This is just the finding of a scanning tool, so there is still a possibility of false positive. That’s why I need to manually verify it.
For the security and confidentiality of the project and client, any further demos and screenshots will only be on a self-built website below, mimicking the real vulnerable website and misconfiguration Akamai WAF.
To verify if there was a bug, I rechecked by reproducting the PoC from the scanning tool. Here, it involved injecting a single quote and observing the PostgreSQL error message in the response.
If I add another quote, the response will return to normal with “success” message.
So this is enough to confirm it's an SQL injection vulnerability. Now, let's move on to the exploitation.
III. Bypassing WAF & Exploitation
Because the application returns database error message, I'll use error-based SQL injection technique here for fast and straightforward to dump a database name which is our goal in this case.
My payload is:
'||(cast((select current_database()) as numeric))||'
But the application return a blocked message indicate that there is a defense mechanism.
I suspect there is some sort of WAF placed in front of the application, detecting and protecting the website from attacks. So let try some bypassing techniques that I have listed in the beginning of the blog.
I have tried obfuscate the payload with incline comments
but it failed:
'||/**/cast((select/**/current_database())/**/as/**/numeric))||'
I continued with Encoding but it still no luck:
'%7c%7c(cast((select%20current_database())%20as%20numeric))%7c%7c'
I have tried various techniques, such as replacing parts of the payload with other statements to bypass blacklists, regex patterns, and signatures, as well as using case variations, but none have been successful.
Luckily, when I looked on the Internet for more ways to bypass, I stumbled upon this solution.
The document mentioned that the WAF might be configured with a limit on the size of the HTTP request body. This means the WAF only inspects up to a certain number of characters in an HTTP POST
request body. This limitation can be exploited by crafting an HTTP POST
request that exceeds the WAF's size limit, placing the payload beyond the inspected portion of the request. It's like slipping a secret message past the guards when they're only checking the first few lines of a letter!
My current mission is to fuzz and discover the WAF's size limit. To do this, I decided to add some junk characters to my input to see if I could slip past the WAF's defenses. I started with 1000 'a's, but the WAF didn't budge.
Undeterred, I doubled it to 2000, but still no success. Then, with a sense of determination, I pushed it to 3000 characters, and BOOM!!! The payload sailed through and bypassed the WAF without a hitch.
Victory at last! We have successfully leaked the database name of the application via an error message.
IV. How can this be fixed
It's crucial for clients to be aware of the size limitations set by their WAF so they can take additional steps to secure their applications. Clients can configure custom rules to block any HTTP request where the body exceeds the size limit. For instance, a rule like:
int(request.headers["content-length"]) >= 2500
can prevent oversized payloads from slipping through the cracks.
V. Final Thoughts
Bypassing a WAF is a high-stakes game of cat and mouse, where every move can determine the security of an application. Our journey from detecting an SQL injection vulnerability to outsmarting a resilient WAF showcased the importance of persistence and creative thinking. Despite initial setbacks with traditional methods, we succeeded by exploiting a clever oversight in the WAF's configuration.
This experience highlights a critical lesson: Security is dynamic and requires constant vigilance. For every defense mechanism, there's a potential bypass waiting to be discovered. It's a reminder to always think outside the box. Developers and security professionals must understand their WAF's capabilities and limitations, configure it to handle edge cases, and employ layered defenses. Additionally, implementing secure coding practices is crucial to fortify applications against potential threats, complementing other defenses like WAFs.
Thanks for reading my first blog. I hope to uncover more bugs soon and share more exciting exploits with you. Have a great day!
Trong bài viết này, chúng ta sẽ khám phá quy trình từ phát hiện SQLi ban đầu đến bypass WAF, khai thác lỗ hổng và thu thập dữ liệu nhạy cảm.
I. Giới thiệu – Bypass WAF là gì?
WAF = Web Application Firewall (Tường lửa ứng dụng web)
Bypass WAF là việc tìm cách lách qua các cơ chế bảo mật được thiết lập để bảo vệ khỏi các cuộc tấn công nhắm vào ứng dụng web.
Mỗi loại WAF có những tính năng và khả năng phát hiện riêng biệt, hiệu quả của các kỹ thuật bypass có thể khác nhau tùy thuộc vào việc triển khai và cấu hình cụ thể của từng WAF.
Có một số kỹ thuật phổ biến để bypass WAF:
- Obfuscation (Làm rối)
- Encoding (Mã hóa)
- HTTP Parameter Pollution (Ô nhiễm tham số HTTP)
- Manipulating Headers (Thao túng Headers)
- Payload Fragmentation (Phân mảnh Payload)
- Case Variations (Biến đổi chữ hoa chữ thường)
- …
Mình có thể thử các kỹ thuật này và quan sát phản hồi của ứng dụng để hiểu cách nó chặn các payload tấn công. Từ đó, chúng ta có thể tìm cách vượt qua các biện pháp bảo vệ này.
Akamai chính là WAF mà mình sẽ đề cập và chia sẻ kỹ thuật bypass trong bài blog lần này.
Lí do mình biết rằng mình đã gặp Akmai WAF là bởi vì khi khai thác sâu lỗi SQLi, mình đã bị chặn và response trả về một trang 403 Access Denied cùng Akamai References Code 18.xx.
Một vài ý bên lề như thế, bây giờ chúng ta hãy xem một ví dụ thực tế nhé.
II. Phát hiện SQL Injection
Trong một lần tham gia kiểm thử bảo mật gần đây, mình có cơ hội kiểm thử trang web của một thương hiệu bán lẻ nổi tiếng. Như mọi khi, theo chiến lược pentest blackbox, mình bắt đầu bằng cách duyệt qua tất cả các endpoint trên trang web. Sau khi thu thập các endpoint cần thiết, mình tiến hành quét bằng công cụ kiểm thử của họ và tự manual test trên từng endpoint.
Sau khi quét xong và lướt qua các kết quả quét của công cụ, mình thấy rất nhiều phát hiện và có một kếtquả đã thu hút sự chú ý của mình.
Tuy nhiên, đây chỉ mới là phát hiện của công cụ quét nên vẫn có khả năng là nó bị sai. Vậy nên mình sẽ cần phải kiểm tra lại một lần nữa.
Để đảm bảo an ninh và bảo mật cho dự án và khách hàng, mọi demo và ảnh chụp màn hình tiếp theo sẽ chỉ được thực hiện trên trang web tự xây dựng mô phỏng trang web thực sự bị lỗi và cấu hình sai của Akamai WAF.
Để xác minh xem có lỗi hay không, mình kiểm tra lại bằng cách tái hiện PoC từ công cụ quét. Ở đây, mình thử chèn một dấu ngoặc đơn và quan sát thấy thông báo lỗi PostgreSQL trong HTTP response.
Nếu mình thêm một dấu ngoặc đơn nữa, phản hồi sẽ trở lại bình thường với thông báo “success”.
Vậy là đủ, ta có thể xác định luôn đây là lỗi SQL Injection. Bây giờ chuyển sang phần khai thác thôi.
III. Vượt WAF & Khai thác
Vì ứng dụng trả về thông báo lỗi cơ sở dữ liệu nên mình sẽ sử dụng kỹ thuật Error-based SQLi luôn để nhanh chóng và dễ dàng trích xuất tên cơ sở dữ liệu, đó là mục tiêu của mình trong trường hợp này.
Payload của mình là:
'||(cast((select current_database()) as numeric))||'
Nhưng ứng dụng trả về thông báo bị chặn cho thấy có một cơ chế bảo vệ.
Mình nghi ngờ có một con WAF nào đó đã được đặt trước ứng dụng để phát hiện và bảo vệ trang web khi nó nhận thấy payload khai thác của mình. Vì vậy, mình đã thử một số kỹ thuật bypass mà mình đã liệt kê ở phần đầu của bài viết.
Mình bắt đầu thử làm rối payload bằng các incline comment
nhưng không thành công:
'||/**/cast((select/**/current_database())/**/as/**/numeric))||'
Tiếp tục với mã hóa nhưng vẫn không ăn thua:
'%7c%7c(cast((select%20current_database())%20as%20numeric))%7c%7c'
Mình đã thử nhiều kỹ thuật khác nhau như thay thế các phần của payload bằng các câu lệnh khác để bypass các regex pattern, signature và blacklist cũng như sử dụng biến đổi chữ hoa chữ thường nhưng không thành công.
May mắn thay, khi mình tìm kiếm trên Internet các cách bypass khác, mình tình cờ tìm thấy giải pháp này.
Tài liệu đề cập rằng WAF có thể được cấu hình với giới hạn về kích thước của phần body trong HTTP Request. Điều này có nghĩa là WAF chỉ kiểm tra đến một số ký tự nhất định trong phần body trong HTTP POST
. Giới hạn này có thể bị khai thác bằng cách tạo một request HTTP POST
vượt quá giới hạn kích thước của WAF, đặt payload ra bên ngoài phần kiểm tra của request. Đó giống như gửi một thông điệp bí mật đằng sau bức thư để qua mặt các lính gác khi họ chỉ kiểm tra vài dòng đầu tiên của một lá thư!
Bây giờ câu hỏi trong đầu mình lúc này đó là: “Làm thế nào để có thể biết được đâu là giới hạn kiểm tra của WAF?”. Để làm điều này, mình sẽ thực hiện kỹ thuật thử sai (fuzzing) và quyết định thêm một số ký tự rác vào đầu vào của body HTTP POST
để xem liệu mình có thể lách qua các biện pháp bảo vệ của WAF hay không. Mình bắt đầu với 1000 ký tự 'a' nhưng response vẫn trả về là “blocked”.
Không nản lòng, mình tăng lên gấp đôi là 2000 nhưng vẫn không thành công. Sau đó, với linh cảm tốt, mình tăng lên 3000 ký tự và BÙM!!! Payload đã vượt qua và bypass Akamai WAF một cách dễ dàng.
Cuối cùng cũng thành công! Mình đã rò rỉ thành công tên cơ sở dữ liệu của ứng dụng qua một thông báo lỗi của PostgreSQL.
IV. Làm thế nào để khắc phục?
Điều quan trọng là khách hàng cần phải nhận thức về các giới hạn kích thước được thiết lập bởi WAF của họ để họ có thể thực hiện các bước bổ sung để bảo mật ứng dụng của mình. Khách hàng có thể cấu hình các quy tắc tùy chỉnh để chặn bất kỳ yêu cầu HTTP nào mà request body vượt quá giới hạn kích thước. Ví dụ, một quy tắc như:
int(request.headers["content-length"]) >= 2500
có thể ngăn chặn payload quá khổ khỏi việc lách qua khe hở này.
V. Lời kết
Bypass một WAF là một trò chơi mèo vờn chuột đầy cam go, trong đó mỗi bước đi có thể quyết định sự an toàn của một ứng dụng. Hành trình từ việc phát hiện lỗ hổng SQL injection đến việc vượt qua Akamai WAF đã cho thấy tầm quan trọng của sự kiên trì và suy nghĩ sáng tạo. Mặc dù gặp phải những thất bại ban đầu với các cách bypass truyền thống, mình đã thành công bằng cách khai thác thông qua một lỗi khá hay trong cấu hình của Akamai WAF.
Case study này nhấn mạnh một bài học quan trọng: ngành bảo mật đang phát triển nhanh chóng và đòi hỏi sự cảnh giác liên tục. Đối với mỗi cơ chế bảo vệ, có một phương pháp bypass tiềm ẩn chờ được khám phá. Đó là lời nhắc nhở để người kiểm thử luôn phải có suy nghĩ đột phá. Các nhà phát triển và chuyên gia bảo mật cần hiểu rõ khả năng và giới hạn của WAF của họ, cấu hình nó để xử lý các trường hợp đặc biệt và áp dụng các biện pháp bảo vệ nhiều lớp. Ngoài ra, việc triển khai secure coding là rất quan trọng để củng cố cho ứng dụng chống lại các tấn công tương tự đi kèm cùng các biện pháp bảo vệ khác như WAF.
Cảm ơn bạn đã đọc bài viết đầu tiên của mình. Mình hy vọng sẽ khám phá thêm nhiều lỗi và chia sẻ thêm nhiều bài hay nữa đến với các bạn. Chào và tạm biệt!
References/ Tài liệu tham khảo
How to confirm if a request has been blocked by Akamai Web Application Firewall (WAF):
- Can WAF inspect all elements and values in request body:
https://community.akamai.com/customers/s/article/Can-WAF-inspect-all-arguments-and-values-in-request-body?language=en_US
Subscribe to my newsletter
Read articles from Nhat “Fo” Anh directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by