Git Product home page Git Product logo

wpgarlic's Introduction

wpgarlic

A proof-of-concept WordPress plugin fuzzer that led to the discovery of more than 300 vulnerabilities in WordPress plugins installed on almost 30 million sites.

The used technique is described in https://kazet.cc/2022/02/03/fuzzing-wordpress-plugins.html

If you want to continue the research, start with less popular plugins - if a plugin achieved at least 10k active installs between October 2021 and January 2024, I have most probably looked at the fuzzer reports (and most focus has been put on plugins having at least 20k active installs). Because there is a lot of randomness in how fuzzer works, some vulnerabilities in these plugins remain undiscovered - but fewer ones.

Fuzzer reports contain a lot of false positives - most of them don't indicate a vulnerability. After seeing a report, first analyze whether the behavior you're observing is indeed a vulnerability or a false positive. Don't spam WPScan/vendors with raw fuzzer reports - provide a PoC exploit instead.

Examples

For obvious reasons, the examples will contain only vulnerabilities that have already been fixed.

Arbitrary file read

Let's assume you are fuzzing responsive-vector-maps in version 6.4.0:

./bin/fuzz_object plugin responsive-vector-maps --version 6.4.0

(to fuzz the latest version, just skip --version).

After the fuzzing finishes (which would take 10-30 minutes for this plugin) you can call:

./bin/print_findings data/object_fuzz_results/

You will see, among others:

responsive-vector-maps fuzzer output example.

That means that the fuzzer detected executing fopen() on a known payload. Most of the payloads contain the word GARLIC in them to facilitate automatic detection in output. You may see or configure them in docker_image/magic_payloads.php.

Then, you may browse the source code and see that indeed the wp_ajax_rvm_import_markers endpoint uses the file content to render output, thus allowing you to read arbitrary files on the server: CVE-2021-24947.

What you see in white is a crash considered interesting (you may modify them or add new ones in crash_detectors.py). Green is the context. In blue you see the report file name (with plugin name), plugin popularity and endpoint name (here: the ajax action name).

The data in yellow are what payloads were injected into what variables.

Reflected XSS

Let's assume you are fuzzing page-builder-add in version 1.4.9.4:

./bin/fuzz_object plugin page-builder-add --version 1.4.9.4

After printing the results, you will see known payload echoed back:

page-builder-add fuzzer output example.

You can then manually test whether indeed this place (remember: in blue you have the endpoint name, here: the menu page name) is vulnerable to XSS. In this case, it is: CVE-2021-25067.

Option update leading to stored XSS

./bin/fuzz_object plugin duplicate-page-or-post --version 1.4.6

After printing the results, you will see update_option being called:

duplicate-page-or-post fuzzer output example.

Analysis of the endpoint's code will tell you that this indeed leads to a stored XSS vulnerability: CVE-2021-25075.

False positives

Unfortunately, for most of the plugins the fuzzer doesn't find any interesting crashes, and for the rest, most of the reports are false positives. For example, if you see:

Call: wp_mail arguments={'to': '[email protected]', 'subject': '[Plugin contact]  - http://GARLICGARLICGARLIC.example.com'}

This can mean, that wp_mail is indeed called, but you don't control the recipient and most of the subject. If you want to be sure, look at the plugin source.

Additional tips for reading fuzzer reports

  • If you see the message; May as well be equal: ... and ... - that means that the mechanism to pretend that a known payload is equal to any other string (described in https://kazet.cc/2022/02/03/fuzzing-wordpress-plugins.html#patched-equality) was triggered.
  • If you see __GARLIC_ACCESSED__ _FILES[files] __ENDGARLIC__ - that means that an uploaded file access was detected. No further checks are currently made - to check whether this is a vulnerability, look at the code.
  • Sometimes what the fuzzer injects into GET, POST etc. parameters is not reproducible in the real world: for example, you can't inject anything into $_GET['page'] if you want a particular menu page to be displayed.

Usage cheatsheet

The first run of fuzzing or of the tests may take about an hour, because we need to build the Docker image with instrumented PHP and WordPress.

Fuzzing a plugin by name

./bin/fuzz_object plugin PLUGIN_SLUG

Fuzzing a theme by name

./bin/fuzz_object theme THEME_SLUG

Fuzzing a plugin from file

You can also install a plugin from a local zip file:

./bin/fuzz_object plugin PLUGIN_FILE_NAME.zip

Printing findings

To print what the fuzzer found, use:

./bin/print_findings data/object_fuzz_results/

Running tests

To run the tests, use:

./bin/test

Warning: the tests take long (more than an hour) and because they check whether the fuzzer would find vulnerabilities, they fail with some probability.

Reformatting code and running linters

wpgarlic uses pre-commit to run linters and format the code. pre-commit is executed on CI to verify that the code is formatted properly.

To run it locally, use:

pre-commit run --all-files

To setup pre-commit so that it runs before each commit, use:

pre-commit install

Manual testing environment

You may start a test environment with only one plugin installed using:

./bin/manual_testing PLUGIN_SLUG|PLUGIN_PATH.zip [version]

You can install a plugin using its slug or from a local zip file.

It will listen on http://127.0.0.1:8001/

There will be two test users in the database:

  • username: admin, password: admin, privileges: administrator
  • username: subscriber, password: subscriber, privileges: subscriber

Extending and configuring the fuzzer

This tool is a proof of concept - this section contains places where it can be improved to find more vulnerabilities.

You may want to edit filtering.py -- it contains the rules that deem a particular crash important or not. If you change them, you may have more false positives, but find more vulnerabilities as well. For example, the only header that I consider interesting when emitted is the Location header, to detect Open Redirect vulnerabilities. That is just one idea and you may have others.

Another file that may be worth extending is docker_image/patch_wordpress.sh. It describes calls to which functions will be logged as interesting.

If you want to inject other payloads (or change the probabilities with which they are injected) edit docker_image/magic_payloads.php and docker_image/fuzz/config.py.

crash_detector.py contans regular expressions that find interesting crashes or interesting information (e.g. e-mails) being exposed.

Fuzzing REST routes as logged-in admin has been disabled as it led to false positives. Uncomment rest_routes_admin in config.DEFAULT_ENABLED_FEATURES to change that.

Fuzzer internals

Blocklists

Some plugins need other ones (e.g. woocommerce) as a dependency. When fuzzing a plugin that has a dependency, we want to fuzz only the chosen plugin and skip the dependency AJAX actions, REST routes and menu pages. We want to fuzz woocommerce actions/routes/pages only when we picked woocommerce to fuzz.

List of dependency actions/routes/pages are called blocklists and are listed in docker_image/blocklists/. Files named common contain the WordPress core actions/routes/pages - we don't want to fuzz these as well.

To update these blocklists, use ./bin/update_blocklists.

FAQ

Fuzzer found something, is this a vulnerability?

Maybe. Install the plugin in a local test environment (for example you may use the one described in the Manual testing environment section) and analyze the bug.

Fuzzer found nothing, is the plugin secure?

Don't assume that. The fuzzer finds some classes of vulnerabilities, but has its limitations.

Fuzzer founds nothing for most of the plugins - the purpose of the tool is rather to massively scan a large number of Wordpress plugins, not to perform comprehensive tests of a single plugin.

Fuzzer found something in one run, but not in the next one. What happened?

This is possible. The fuzzer chooses payloads randomly, and introduces randomness in other places (e.g. how the== operator should behave in cases described in https://kazet.cc/2022/02/03/fuzzing-wordpress-plugins.html#patched-equality).

Doesn't work? Have a question?

File a Github ticket or e-mail me: [email protected].

wpgarlic's People

Contributors

kazet avatar dawid-czarnecki avatar dependabot[bot] avatar

Stargazers

Hari Sankar. R S avatar  avatar Sven Kauber avatar Casey Strouse avatar Charaf Mrah avatar esTse avatar Ali Yar Khan avatar  avatar Martin Stepanek avatar Usama Arshad avatar Dallas Crilley avatar x64sec avatar  avatar  avatar Peter Thaleikis avatar  avatar Hossein Shourabi  avatar Francesco Carlucci avatar XX avatar Hsiang Shen, Chiu avatar  avatar  avatar SoDakHib avatar 이종학 avatar  avatar Alec Akin avatar Łukasz Kajdan avatar Trenton Gorman avatar Greedun avatar Martin Kubečka avatar hackintoanetwork avatar Robert DeVore avatar  avatar Ayushdeep avatar  avatar Abdillah Hasny avatar  avatar 0xSP3C14LN1NJ4 avatar h3dg3h0g avatar Achmad Adhikara avatar  avatar Nhien.IT avatar  avatar Z3ROD avatar Daria avatar  avatar  avatar VΞИDΞΓΓΛ™ avatar Med Khalil avatar  avatar  avatar xs xsa avatar  avatar hirak0 avatar Never Mind avatar  avatar Henri Salo avatar  avatar Thomas avatar James Martindale avatar Yasser Elsnbary avatar Chris Caldwell avatar Monstersec  avatar Vay3t avatar Felipe Montecino avatar  avatar Ibai avatar David Wittman avatar 4Ark avatar  avatar  avatar Nick avatar Mestre Karin avatar maple avatar s1g0day avatar  avatar James Hunt avatar Josh Rising avatar Amaury Balmer avatar  avatar Presian Yankulov avatar Jaikishan Tulswani avatar Vincenzo Marcovecchio avatar MN Arifin avatar  avatar  avatar  avatar biubiu avatar Mount4in avatar  avatar Tyler Longren avatar Aaditya Purani avatar  avatar Wumpus avatar  avatar vishnummv avatar Abell avatar 5l1v3r1 avatar  avatar  avatar

Watchers

 avatar  avatar Abdillah Hasny avatar Josh Rising avatar Peter Thaleikis avatar Dallas Crilley avatar Wumpus avatar 求知鱼 avatar  avatar hirak0 avatar

wpgarlic's Issues

Question about proxy

I would like to pass each fuzzing request through a proxy server (such as burp suite).
Could you please help me and tell me how to do this?

Maybe need Usage

I want to more details to know how to use this tool, I'm a learner,so i want to test poc by this tools, i want to kown which file shoud i use first,maybe ..?filtering.py or fuzzer_container.py....

ZeroDivisionError when trying to print the findings

Hello there, thank you for your research, I have a question regarding the tool. At first after installing, I had to tweak the dependencies versions a little bit to get it to work, and it worked perfectly afterward and I was able to fuzz and see the findings of the fuzzing.
But as soon as I started to fuzz the next plugin, the findings printer stopped working properly and it started to raise an Exception for Zero Division Error:

┌──(venv)─(root@kali)-[~/wpgarlic]
└─# bin/print_findings data/plugin_fuzz_results/
0%| | 0/1 [00:00<?, ?it/s]data/plugin_fuzz_results/pdf-generator-for-wp_4b256ea0c30ed8675326896c750f21be.json
Nothing found in pdf-generator-for-wp_4b256ea0c30ed8675326896c750f21be.json. Archiving the report...
data/plugin_fuzz_results/scanned/pdf-generator-for-wp_4b256ea0c30ed8675326896c750f21be.json: 84.3% -- replaced with data/plugin_fuzz_results/scanned/pdf-generator-for-wp_4b256ea0c30ed8675326896c750f21be.json.gz
100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:34<00:00, 34.74s/it]
Unique filepaths total: 1
Filepaths with report printed: 0 (0.00%)

┌──(venv)─(root@kali)-[~/wpgarlic]
└─# bin/print_findings data/plugin_fuzz_results/
0it [00:00, ?it/s]
Unique filepaths total: 0
Traceback (most recent call last):
File "/root/wpgarlic/print_findings.py", line 250, in
typer.run(print_findings_from_folder)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/typer/main.py", line 864, in run
app()
File "/root/wpgarlic/venv/lib/python3.9/site-packages/typer/main.py", line 214, in call
return get_command(self)(*args, **kwargs)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/click/core.py", line 1128, in call
return self.main(*args, **kwargs)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/click/core.py", line 1053, in main
rv = self.invoke(ctx)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/click/core.py", line 1395, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/click/core.py", line 754, in invoke
return __callback(*args, **kwargs)
File "/root/wpgarlic/venv/lib/python3.9/site-packages/typer/main.py", line 500, in wrapper
return callback(**use_params) # type: ignore
File "/root/wpgarlic/print_findings.py", line 245, in print_findings_from_folder
f"({100.0 * num_paths_with_printed_reports / len(file_names):.02f}%)"
ZeroDivisionError: float division by zero

I deleted all containers and images and deleted the project folder and rebuilt the whole thing from scratch but that sadly didn't help.
I can see that the Fuzzing is happening in the first stage and the huge findings .Json file being created, but then the reporter prints that it couldn't find anything even though I'm testing the same plugin I tested before and I'm sure that there are some findings at least.
Do you have an Idea what might be causing this and how to fix it ?
Thanks a lot !

Not Getting the Expected Behavior

Hi,

When executing the following command, I don't get any results:

./bin/fuzz_plugin responsive-vector-maps --version 6.4.0
./bin/print_findings data/plugin_fuzz_results/
  0%|                                                                                             | 0/1 [00:00<?, ?it/s]data/plugin_fuzz_results/responsive-vector-maps_2ebc606988056f9282e287708b380297.json
Nothing found in responsive-vector-maps_2ebc606988056f9282e287708b380297.json. Archiving the report...
data/plugin_fuzz_results/scanned/responsive-vector-maps_2ebc606988056f9282e287708b380297.json:	 11.5% -- replaced with data/plugin_fuzz_results/scanned/responsive-vector-maps_2ebc606988056f9282e287708b380297.json.gz
100%|████████████████████████████████████████████████████████████████████████████████████| 1/1 [00:00<00:00, 677.05it/s]
Unique filepaths total: 1
Filepaths with report printed: 0 (0.00%)

The only change I made is changing the version to "3.3" in docker-compose.yaml
Here are the logs of the installation. Let me know if you spot any issue:

wpgarlic_install_logs.txt

wait-for-it.sh: waiting for db1:3306 without a timeout

Hi there,
When I started fuzzing, I got this message, what's the problem?
[+] Running 3/3
⠿ Container wpgarlic-db1-1 Started 1.0s
⠿ Container wpgarlic-dns1-1 Started 1.0s
⠿ Container wordpress1 Started 1.9s
wait-for-it.sh: waiting for db1:3306 without a timeout

Also, when I run these containers, the mysqld uses 99% of the CPU.

I really appreciate any help you can provide.

Failing to fuzz folder containing plugins

I'm unable to fuzz multiple plugins located in a folder using the --file-or-folder-to-fuzz option, when I've tried directly running ./bin/fuzz_plugin <folder path>, this led to an error:

Traceback (most recent call last):
  File "/home/user/wpgarlic/fuzz_plugin.py", line 234, in <module>
    typer.run(fuzz_plugin)
  File "/home/user/wpgarlic/fuzz_plugin.py", line 69, in fuzz_plugin
    assert all(
AssertionError

Any guidance or a potential fix would be appreciated.

Running on Ubuntu 22.04.3 LTS on WSL2.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.