Exploiting error-based SQL injections via xPath functions.
All began by adding a single quote, the most common SQL injection testing character.

Server will responde with a visible unhandled error.
You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '''' ORDER BY fecha DESC' at line 1

Quick explanation why the error is displayed, the unhandled error occurs first because the query has not been parameterized in the DB (allowing the introduction of unexpected queries) and when the error throw from the DB is not capture in the backend server.
Once SQL injection has been identified, time to validate if it can be exploited. Identify != exploit.
One way to validate the injection is to get the number of columns from the current query:

Once the number of columns is obtained (9 columns), use this information to form a new union query. The new query allows us having control to make own calls to the DB.

However a ‘403 Forbidden’ response is received. And in case keep trying either obfuscating/encoding characters next time will be a block.

But even from a block response you can get information. And Imunify360 is used as WAF protection.
Knowing the used technology, could try to find specific bypass methods. With a quick search, multiple results come out, such as:

Does not work. The WAF will have been updated since the past 2020.
As everything in this direction is getting complicated or failing, is a good time to change, look for an alternative way that the Imunify360 WAF does not expect.
There is an alternative way to exploit, indirectly the unhandled error (read it some time ago). The idea is to be able to control the error message. Have the ability to decide what data to show in the trace.
To do that, let’s talk first about XML Path Language (XPath). More information about what XPath is.

Summarizing XPath is a language originally built to search and find elements in an XML. Later also introduced in SQL language to retrieve data from a database.
XPath was implemented in MySQL in version 5.1. Of all the functions, the interesting one for this case is ExtractValue(), allows you to read from an XML and return the desired attribute. ExtractValue(xml_frag, xpath_expr) receives xml_frag as the first parameter, which will be the name of the attribute, and xpath_expr as the second parameter, which will be an XPath expression.

Understanding how the function works, now let’s try to validate the sqli.
Quick remember! don’t have to use the ExtractValue function correctly, but make it fail to produce a new error message “controlled” by us.
To better understand this part I am going to do some tests locally simulating the exploitation.

The error generated from the second query is the one that can NOT be handled by us. So ExtractValue comes to the game, xml_frag parameter will look for an attribute = column THAT DOES NOT EXIST, for example a column called semicolon ‘ ; ‘ and from xpath_expr a MySQL function will be used. This way when the SQL query fails (beacuse the xml_frag semicolon) the function will be executed.

0x3b is the hexadecimal representation of the semicolon. XPath injection works, but not quite. What’s weird? Well it seems that not all the expected output is observed. @localhost it’s not the current user but root@localhost.
This occurs because functions in XPath have a character limitation. Therefore, to be able to visualize all the output, multiple functions have to be concatenated at the same time.

XPath injection is now tested on the web
noticia'+and+extractvalue(0x3b,+concat(0x3b,current_user()));--+-

Try to read the first table of the DB.
noticia'+and+extractvalue(0x3b,+concat(0x3b,+(select+concat (0x3b,table_name)+from+infromation_schema.tables+where+table_schema= 'dbXXXXrod'+limit+0,1)));--+-

This could now be automated and exfiltrate the entire DB.
The report that I read a long time ago and that helped me for this exploitation is:
https://medium.com/r3d-buck3t/error-based-xpath-sql-injection-in-openemr-2abbc0379ac5
