action=tribe_dropdown, to trigger the wp_ajax_nopriv_tribe_dropdown action
source=search_posts, to call the right function
args[nopaging]=true, to disable paging in the WP_Query object and list all data
args[post_status][]=all, to list all posts, including private ones
Because of the vulnerable code in The Events Calendar plugin, it is possible to list the title of all posts, including draft, password-protected and private ones.
Attempt to dump a post content
Being able to read the title of all posts is interesting but it would be way more interesting to dump the actual content of any post published. The WP_Query object enables to search for specific patterns in posts. It is therefore theoretically possible to dump the content of a post.
When performing a search using WP_Query, multiple rules are implemented to soften the search and returns as many potential results as possible. However these rules make it difficult to use WP_Query to recover the full content of an article. While exploring the source code of WP_Query, we found multiple arguments that could help to dump the content of a post using the previous vulnerability:
p: defines the id of the article to search for. It can be useful to prevent searching in all posts created. Be careful this argument will not work for private posts.
search_columns: list of columns in the database where to look for matches. There is a whitelist so that only the following columns are allowed:
sentence: if enabled, the search term is considered as a single block. No parsing is performed and it ensures the exact searched content is in the searched columns.
By mixing these parameters, it is possible to search for a specific precise content and to retrieve the content of an article, character by character.
Obviously, this search method is slow being in O(n*m)where n is the number of chars in the post content and m is the size of the alphabet. It is possible to reduce the size of m by first checking if a character is present in the content. This is doable thanks to a rule in the search pattern stating that if the pattern starts with -, WP_Query will perform a reverse search. Therefore, if searching for -c returns a result, it means that the c char is not in the post content.
We scripted this search method and confirmed it is possible to recover short posts in a reasonable time, significantly increasing the severity of the vulnerability.
Remediation
To fix the vulnerability, the vendor has implemented a protection that prevents users from manipulating any key other than taxonomy and post_type in the args parameter, and has set post_status to publish. This simple correction effectively prevents requests for data on private posts. Moreover, the method described to dump the content of a post is no longer exploitable.
Simple, but efficient!
Conclusion
At Patrowl, we love automated and continuous pentest. Our unique scanning and testing automation guides us into manual searching to ensure we only return real vulnerabilities to our customers. We will continue to look for new vulnerabilities based on findings we get on our clients' assets and stay tuned for future posts!