SSRF逆向分析

0x00 前言

之前有复现过一些漏洞,但是每次按照别人的思路复现完了之后感觉还是有很多疑问,知道了怎么做但是不知道为什么这么做,所以这次我尝试自己从补丁一步步找到攻击链,构造poc。

0x01 收集情报

补丁地址:

https://gitee.com/ComsenzDiscuz/DiscuzX/commit/41eb5bb0a3a716f84b0ce4e4feb41e6f25a980a3

查看补丁,发现如下:

删去了followlocation,也就是说对于301/302请求,curl不会去跟踪跳转。

既然这里存在一个跳转ssrf,下面就是逆向调用链,找到程序的入口。

0x02 尝试逆向找到触发点

首先这个存在漏洞的函数是_dfsockopen,通过Ctrl+Alt+F大法找到了位于function_core.php的dfsockopen方法。

继续向上找,找到了一处import_block方法。

通过对dfsockopen的第一个参数进行分析,发现其刚好是import_block的第一个参数经过一些处理之后的结果。

由于参数可控,继续向上。

鸡冻人心的发现!第一个参数直接以$_GET传了进去!

0x03 尝试构造payload

下面看一下如何访问到这个语句:

首先,直接通过文件肯定是访问不了的(L10-12)。下面根据L19和L21确定url中基本要必须存在的参数。经过一系列的尝试和Ctrl+Alt+F,终于找到了入口:

/upload/admin.php?action=blockxml&operation=add

跟进一下submitcheck()

继续跟进getgpc()

大概就是返回$_GET[$k],由于这里的$k就是从前面的submitcheck('addsubmit')传进来的,所以这里只要保证$_GET['addsubmit']即可,构成的url如下:

/upload/admin.php?action=blockxml&operation=add&addsubmit=test

继续跟,

可以看到getgpc返回了$_GET['addsubmit']的值,由于我们的url参数中有此参数,因此进入到了else语句块。继续跟进submitcheck

这里又有一个相同的getgpc(),由于参数跟刚刚也相同,就不继续跟了,直接进入到else语句块。可以看到,首先22行有个if语句,必须把条件满足成True,否则是False的话就直接进入Else语句块,这条链就直接中断掉了。仔细看一下这个if条件:

$allowget || ($_SERVER['REQUEST_METHOD'] == 'POST' &&
!empty($_GET['formhash']) && $_GET['formhash'] == formhash() &&
empty($_SERVER['HTTP_X_FLASH_VERSION']) &&
(empty($_SERVER['HTTP_REFERER']) ||      strncmp($_SERVER['HTTP_REFERER'], 'http://wsq.discuz.com/', 22)
=== 0 || preg_replace("/https?:\/\/([^\:\/]+).*/i", "\\1",
$_SERVER['HTTP_REFERER']) == preg_replace("/([^\:]+).*/", "\\1",
$_SERVER['HTTP_HOST'])))

最外层是个or,如果$allowget是True就直接省事儿了,可是这是此方法的第二个参数,默认为0,pass。剩下的逻辑如下:

1)必须是POST请求 &&

2)GET请求中必须有formhash参数 &&

3)formhash的值必须等于formhash() &&

4)请求头中没有HTTP_X_FLASH_VERSION &&

5.1)refer为空 ||

5.2)referer的值以http://wsq.discuz.com/开头 ||

5.3)referer与host的主机名部分必须相同

第1、4、5条件好满足,直接抓包改即可。主要看第二个请求和第三个请求,即如何获取这个formhash。看一下函数定义:

其大致是计算一个数的MD5,这个数由几个$_G变量组成。既然不是一个固定的值,那么首先肯定是服务端先发给客户端,然后客户端才能带着这个$_GET['formhash']来进行请求,下面全局搜一下formhash,发现很多页面中都有这个字段:

然后随手在页面上查找一下,没想到真找到了:

(经过一些测试,这里有个比较坑的点是这个formhash在同一个session请求中是不会变的,不过前台和后台的formhash不是同一个,你不能拿前台获取的formhash作为参数去访问后台的接口)。

formhash的问题到这里就解决了,会看一下上面的条件,构成的url暂时如下:

POST ..../upload/admin.php?action=blockxml&operation=add&addsubmit=test&formhash=2b23ba6f

并且去掉referer头。

请求之后可以发现,成功进入了if语句,然后顺其自然的到了return True。

然后就终于回到了最开始的地方,成功调用import_block()

由于这里需要$_GET['xmlurl'],我们暂且传入http://127.0.0.1:2222。

可以看到,最后url赋值给了$signurl,其值变成:

http://127.0.0.1:2222?charset=utf-8&clientid=&op=getconfig&sign=

没有什么太大的变化,继续跟进后就到了最开始说的那个可能存在ssrf的_dfsockopen方法了。通过下图可以看到,先是在33行调用parse_url对用户传来的url进行解析,然后调用_isLocalip()来检查host是否是内网地址,如果是内网地址则直接return掉。所以就算这里存在ssrf,我们的url中也是不能直接传内网地址进来的。

接着看,这里在88行发送了请求,我在这次请求中传入的url是:upload/admin.php?action=blockxml&operation=add&addsubmit=test&formhash=2b23ba6f&xmlurl=http://127.0.0.1:2222

这里看一下我本地监听的2222端口:

访问成功了。

下面的整理下思路,由于程序对内网地址进行了限制,导致了除127.0.0.1之外的内网地址都会直接return掉,因此这里我们需要通过一个301跳转,来实现绕过程序对内网url的限制。

可是如果想要curl自动重定向到第一个url返回的地址中去,就必须先要将此curl的CURLOPT_FOLLOWLOCATION属性设置为true才行。然而这一点在本文一开始就已经确认了:

下面就可以通过在vps上上传一个301跳转的php脚本,内容如下:

下面把我们之前的payload中的xmlurl改成我的公网vps的ip,然后重放,同时在本地监听9999端口。

请求结果如下,可以发现,本地的9999端口果然收到了discuz-curl发来的请求!

我的vps的http日志:

至此,这条ssrf的攻击链就已经形成了。

0x04 总结

这次跟下来还是学到了一些东西的,比如构造payload时会遇到的一些坑,然后自己对ssrf也有了跟深入的一些理解。

Discuz3.4-SSRF-从触发点到构造payload的更多相关文章

  1. HGAME-week2-web-wp

    hgame第二周总结 1.webpack-engine 我不懂,但是真的刚打开就出来了,一脸懵逼(wp说是sourcemap没关 hgame{D0nt_f0r9et_2_ClOs3_S0urce_m@ ...

  2. 学习xss模拟构造攻击(第一篇)

    本文作者:i春秋签约作家——rosectow 0×00前言 XSS又名叫CSS全程(cross site scriptting),中文名跨站脚本攻击,目前网站的常见漏洞之一,它的危害没有像上传漏洞,s ...

  3. discuz 3.x ssrf分析

    discuz 3.x版本ssrf漏洞分析 漏洞促发点\souce\module\forum\forum_ajax.php 最后看到了这里 ***$_GET['action']='downremotei ...

  4. XSS Payload深入分析整理

    几种加载XSS Payload的不常见标签 众所周知,一种调用JavaScript的方法就是在元素类型上使用事件处理器(Event Handler),通常的一种方法类似: <img src=x ...

  5. CTF SSRF(服务器端伪造请求)

    目录 CTF SSRF(服务器端伪造请求) 一.概念 二.危害 三.漏洞挖掘与判断 四.相关函数 五.IP绕过 六.Gopher协议 1.使用限制 2.构造payload CTF SSRF(服务器端伪 ...

  6. SSRF绕过姿势

    0x00 什么是SSRF? SSRF(Server-Side Request Forgery,服务器端请求伪造):是一种由攻击者构造形成由服务器端发起请求的一个漏洞. SSRF 攻击的目标是从外网无法 ...

  7. SSRF和XSS-filter_var(), preg_match() 和 parse_url()绕过学习

    0x01:url标准的灵活性导致绕过filter_var与parse_url进行ssrf filter_var() (PHP 5 >= 5.2.0, PHP 7) filter_var — 使用 ...

  8. Vue中的Xss构造

    首发tools:https://www.t00ls.net/thread-59512-1-1.html 存储型XSS 最近做测试的时候碰到了一个前端页面使用了Vue框架的项目 在测试XSS漏洞的过程中 ...

  9. CTFHub-技能树-SSRF

    SSRF 目录 SSRF 1.内网访问 2.伪协议读取文件 3.端口扫描 4.POST请求 5.上传文件 6.FastCGI协议 7.Redis 8.URL Bypass 9.数字IP Bypass ...

随机推荐

  1. 网易面经(Java开发岗)

    网易面经(Java岗) 网易两面面经整理 岗位:我投递的是杭研所的Java开发岗位.行程:半天的时间南京=杭州之间穿行,单程2个小时,从杭州东站=网易大厦,单程1个小时(如果能买到城站高铁动车票可以从 ...

  2. Mybatis 系列8

    上篇系列7 介绍了insert.update.delete的用法, 本篇将介绍select.resultMap的用法. select无疑是我们最常用,也是最复杂的,mybatis通过resultMap ...

  3. Entity Framework分页扩展

    Entity Framework分页在我初入门时总是困扰这我,无论是SQL分页还是Entity Framework的分页,总是显得那么麻烦,因此对于Entity Framework单独封装了分页. 一 ...

  4. 我们常说的 CAS 自旋锁是什么

    CAS(Compare and swap),即比较并交换,也是实现我们平时所说的自旋锁或乐观锁的核心操作. 它的实现很简单,就是用一个预期的值和内存值进行比较,如果两个值相等,就用预期的值替换内存值, ...

  5. 详解CSS选择器、优先级与匹配原理【转】

    作为一个Web开发者,掌握必要的前台技术也是很重要的,特别是在遇到一些实际问题的时候.这里给大家列举一个例子: 给一个p标签增加一个类(class),可是执行后该class中的有些属性并没有起作用.通 ...

  6. ADC0832的应用

    ADC0832是美国国家半导体公司生产的一种8位逐次比较型CMOS双通道A-D转换器,采用5V电源电压供电,模拟电压输入范围为0~5V,内部时钟250KHz时转换速度为32微秒. 仿真图为: 程序为: ...

  7. Http协议、Tomcat、servlet

    HTTP协议 Http,超文本传输协议是互联网上最广泛的一种网络协议,所有的www文件都必须遵守这个标准. Http协议由http请求和http响应组成 http请求: 1.请求行 请求方式 POST ...

  8. Python_字符串的映射与可变字符串的应用

    ''' maketrans().translate() maketrans()方法用来生成字符映射表,而translate()方法则按映射表中定义的对应关系转换并替换其中的字符,使用这两个方法的组合可 ...

  9. mysql 和 oracle 的一些小知识

    有很多应用项目, 刚起步的时候用MYSQL数据库基本上能实现各种功能需求,随着应用用户的增多,数据量的增加,MYSQL渐渐地出现不堪重负的情况:连接很慢甚至宕机,于是就有把数据从MYSQL迁到ORAC ...

  10. Atlas的优缺点及测试结论

    优点 1,实现了读写分离(并通过hint/*master*/可强制走主库,并且加入了权重配置可进行读的负载均衡 2,自身维护了一套连接池,减少了创建连接带来的性能消耗 3,支持DB动态上下线,方便横向 ...