One day I felt like reviewing the source code of some random CMS and I picked CMSMS. This is totally random and I did this to kill boredom.
Remote Code Execution – CVE-2017-8912
In admin/editusertag.php you can create custom user defined tags in which evil PHP functions are not blacklisted.
POST /cms/cmsimple/admin/editusertag.php?_sk_=2a7da2216d41e0ac&userplugin_id=4 HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 6.2; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: cms_admin_user_id=1; cms_passhash=4df45e48ad5885afabe27e446666421b; _sk_=2a7da2216d41e0ac; CMSSESSIDacef9ab5f31b=mckpbvrmtj7n6ri53kiol718c5
I found this post by Alex Ionescu pretty interesting. I recreated the poc and wrote position independent shellcode. It’s more like executing shellcode directly by the windows loader.
One could develop complete malware by dynamically locating the base address of kernel32.dll and once you locate the functions LoadLibraryA and GetProcAddress, you can load any library in the system and find the exported symbols, in which you have complete access to the win32 API.
You don’t need to specifically write position independent code using assembly. You can directly code in C/C++ and extract the opcodes.
For example using the ‘InMemoryOrderModuleList’ LDR_DATA_TABLE_ENTRY located in the PEB->LDR we can get the base address of kernel32.dll. Usually kernel32.dll can be found in the third LDR_MODULE in the double linked list. If you have done shellcoding under Windows these things should be familiar.
The traditional in-band method in INSERT, UPDATE injections would be by fixing the query. For example in INSERT statements one can simply fix the query, comment out the rest and extract the data once it is echoed out by the application. Same goes with the UPDATE statement, but only if the query has more than one column we can fix the query. What if we face a situation where UPDATE or INSERT has one column or simply we don’t know the exact query to fix? What if mysql_error() is not echoed out?
Let’s look at the following scenario. For simplicity’s sake let’s not make things complex. The updated username is also echoed back to us. How can we inject in this scenario?
$query = "UPDATE users SET username = '$username' WHERE id = '$id';";
The parameters are as follows for the update query.
Recently I was researching on different in-band and out-of-band techniques we can apply in these situations.
To understand my technique let’s look at how MySQL handles strings. Basically a string is equal to ‘0’ in MySQL. Let me prove it.
mysql> select 'osanda' = 0;
| 'osanda' = 0 |
| 1 |
mysql> select !'osanda';
| !'osanda' |
| 1 |
What if we add digits to a string? It would be same as adding a value to 0.
mysql> select 'osanda'+123;
| 'osanda'+123 |
| 123 |
Out-of-band injections are very well researched when it comes to MSSQL and Oracle. But in MySQL I noticed that this topic is not well researched. I thought of researching about this topic based on my experiences in SQL injections. For this purpose we can take advantage of functions such as load_file() and select … into outfile/dumpfile. Apart from that we can also steal NetNTLM hashes and perform SMB relay attacks. All this is possible only in MySQL under Windows.
What is Out-of-Band Injection?
These attacks involve in alternative channels to extract data from the server. It might be HTTP(S) requests, DNS resolutions, file systems, E-mails, etc depending on the functionality of the back-end technology.
Limitations in MySQL
In MySQL there exists a global system variable known as ‘secure_file_priv’. This variable is used to limit the effect of data import and export operations, such as those performed by the LOAD DATA and SELECT … INTO OUTFILE statements and the LOAD_FILE() function.
- If set to the name of a directory, the server limits import and export operations to work only with files in that directory. The directory must exist, the server will not create it.
- If the variable is empty it has no effect, thus insecure configuration.
- If set to NULL, the server disables import and export operations. This value is permitted as of MySQL 5.5.53
Before MySQL 5.5.53 this variable is empty by default, hence allowing us to use these functions. But in the versions after 5.5.53 the value ‘NULL’ will disable these functions.
To check the value of this variable you can use any of these methods. The ‘secure_file_priv’ is a global variable and it’s a read only variable, which means you cannot change this during runtime.
show variables like "secure_file_priv";
Starting from MySQL 5.5 and above the default storage engine was known as the InnoDB. In MySQL versions 5.5 and above if you do a “select @@innodb_version” you can see the version of the InnoDB, which is almost same as your MySQL version.
But in MySQL 5.6 and above I noticed 2 new tables by InnoDB. “innodb_index_stats” and “innodb_table_stats”. Both these tables contains the database and table names of all the newly created databases and tables.
The MySQL documentation explains these two tables as follows.
The persistent statistics feature relies on the internally managed tables in the mysql database, named innodb_table_stats and innodb_index_stats. These tables are set up automatically in all install, upgrade, and build-from-source procedures.
For injection purposes let’s take the “innodb_table_stats” table. Unfortunately InnoDB doesn’t store columns.
If you simply do “show tables in mysql” you can view this from your localhost.
I was doing some random experiments using assembly and C. This is a simple example in packing 2 numbers inside a register in assembly. Let’s assume
We want to store these 2 values inside the dl register. The dl register is of 8 bits, so 5 + 3 = 8 bits
; al < 2 ^ 5, bl < 2 ^ 3
mov al, bl
shl dl, 3
or dl, bl ; xor would also work fine
mov cl, dl ; Make a copy of dl
and dl, 111b ; Extract lowest 3 bits (b)
mov bl, dl
shr cl, 3 ; Extract highest 5 bits (a)
mov al, cl
I don’t know how to begin with, I’m not a expert experienced reverse engineer. I actually entered this field recently. Before that I had experience with basic exploit development and solving crackmes. But reverse engineering is not about solving a hard crackme, anyone can code a hard algorithm. However at the beginning some people said that this course is hard for me and not suitable for me. As the course title suggests “Advanced Reverse Engineering of Software” it is surely advanced to a level. I haven’t spent years in this field but I dedicated the last few months in this area and I really learned a lot from this course. If you ask the existing people in this field how to enter this area 9/10 people would recommend the tutorial series of “Lena151”. Actually those tutorials do not give a complete idea and is a bad choice. I’m not the only person who says this.
I have been thinking about why this happens. Thinking back to myself, I started learning reverse engineering by reading the Lena151 tutorials. I thought they were awesome until Daeken told me that was an awful approach to learn reverse engineering.
At first I didn’t understand why they were so bad. After all, Lena’s tutorials had taught me how to crack my first software.
You can check his post from here.
The things I learned in here really helped me to take my C/C++/ASM skills to the next level. Each topic I learned helped me research more and more into the subject.