Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved. |
| 3 | * |
| 4 | * This program and the accompanying materials are made available under the |
| 5 | * terms of the Eclipse Public License v. 2.0, which is available at |
| 6 | * http://www.eclipse.org/legal/epl-2.0. |
| 7 | * |
| 8 | * This Source Code may also be made available under the following Secondary |
| 9 | * Licenses when the conditions for such availability set forth in the |
| 10 | * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| 11 | * version 2 with the GNU Classpath Exception, which is available at |
| 12 | * https://www.gnu.org/software/classpath/license.html. |
| 13 | * |
| 14 | * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| 15 | */ |
| 16 | |
| 17 | import java.io.*; |
| 18 | import java.net.*; |
| 19 | import com.sun.ejte.ccl.reporter.*; |
| 20 | |
| 21 | /** |
| 22 | * Unit test for Issus 8585: RequestDispatcher directory traversal vulnerability |
| 23 | * |
| 24 | */ |
| 25 | public class WebTest { |
| 26 | |
| 27 | private static SimpleReporterAdapter stat |
| 28 | = new SimpleReporterAdapter("appserv-tests"); |
| 29 | |
| 30 | private static final String TEST_NAME |
| 31 | = "request-dispatcher-directory-traversal"; |
| 32 | private static final String TEST_NAME2 |
| 33 | = "request-dispatcher-directory-traversal-type2"; |
| 34 | private static final String TEST_NAME3 |
| 35 | = "request-dispatcher-directory-traversal-type3"; |
| 36 | |
| 37 | private static final String EXPECTED = "This is OK."; |
| 38 | |
| 39 | private String host; |
| 40 | private String port; |
| 41 | private String contextRoot; |
| 42 | private String appserverTestPath; |
| 43 | private String adminPort; |
| 44 | |
| 45 | public WebTest(String[] args) { |
| 46 | host = args[0]; |
| 47 | port = args[1]; |
| 48 | contextRoot = args[2]; |
| 49 | appserverTestPath = args[3]; |
| 50 | adminPort = args[4]; |
| 51 | } |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 52 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 53 | public static void main(String[] args) { |
| 54 | stat.addDescription("Security Vulnerability test for RequestDispatcher directory traversal"); |
| 55 | WebTest webTest = new WebTest(args); |
| 56 | webTest.doTest(); |
| 57 | stat.printSummary(TEST_NAME); |
| 58 | } |
| 59 | |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 60 | public void doTest() { |
| 61 | try { |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 62 | invoke(); |
| 63 | } catch (Exception ex) { |
| 64 | stat.addStatus(TEST_NAME, stat.FAIL); |
| 65 | ex.printStackTrace(); |
| 66 | } |
| 67 | try { |
| 68 | invokeValidationTestForDoubleDot(); |
| 69 | } catch (Exception ex) { |
| 70 | stat.addStatus(TEST_NAME2, stat.FAIL); |
| 71 | ex.printStackTrace(); |
| 72 | } |
| 73 | try { |
| 74 | invokeValidationTestForColon(); |
| 75 | } catch (Exception ex) { |
| 76 | stat.addStatus(TEST_NAME3, stat.FAIL); |
| 77 | ex.printStackTrace(); |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | private void invoke() throws Exception { |
| 82 | |
| 83 | Socket sock = null; |
| 84 | OutputStream os = null; |
| 85 | InputStream is = null; |
| 86 | BufferedReader bis = null; |
| 87 | try { |
| 88 | System.out.println("Host=" + host + ", port=" + port); |
| 89 | sock = new Socket(host, new Integer(port).intValue()); |
| 90 | os = sock.getOutputStream(); |
| 91 | String get = "GET " + contextRoot + "/page.jsp?blah=/../WEB-INF/web.xml HTTP/1.1\n"; |
| 92 | System.out.println(get); |
| 93 | os.write(get.getBytes()); |
| 94 | os.write("Host: localhost\n".getBytes()); |
| 95 | os.write("\n".getBytes()); |
| 96 | is = sock.getInputStream(); |
| 97 | bis = new BufferedReader(new InputStreamReader(is)); |
| 98 | String line = null; |
| 99 | boolean isExpected = false; |
| 100 | while ((line = bis.readLine()) != null) { |
| 101 | System.out.println(line); |
| 102 | if (line.equals(EXPECTED)) { |
| 103 | isExpected = true; |
| 104 | break; |
| 105 | } |
| 106 | } |
| 107 | if (isExpected) { |
| 108 | stat.addStatus(TEST_NAME, stat.PASS); |
| 109 | } else { |
| 110 | System.err.println("Missing expected response: " + EXPECTED); |
| 111 | } |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 112 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 113 | } finally { |
| 114 | try { |
| 115 | if (os != null) os.close(); |
| 116 | } catch (IOException ex) {} |
| 117 | try { |
| 118 | if (is != null) is.close(); |
| 119 | } catch (IOException ex) {} |
| 120 | try { |
| 121 | if (sock != null) sock.close(); |
| 122 | } catch (IOException ex) {} |
| 123 | try { |
| 124 | if (bis != null) bis.close(); |
| 125 | } catch (IOException ex) {} |
| 126 | } |
| 127 | } |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 128 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 129 | private void invokeValidationTestForDoubleDot() throws Exception { |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 130 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 131 | Socket sock = null; |
| 132 | OutputStream os = null; |
| 133 | InputStream is = null; |
| 134 | BufferedReader bis = null; |
| 135 | try { |
| 136 | // Validating the ".." file traversal check |
| 137 | sock = new Socket(host, Integer.valueOf(adminPort)); |
| 138 | os = sock.getOutputStream(); |
| 139 | String get = "GET " + "/theme/META-INF/%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af" |
| 140 | + "%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af" |
| 141 | + "%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af" |
| 142 | + "%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af" |
| 143 | + "%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%af%c0%ae%c0%ae" |
| 144 | + "%c0" + appserverTestPath + "/domains/domain1/config/local-password HTTP/1.1\n"; |
| 145 | System.out.println(get); |
| 146 | os.write(get.getBytes()); |
| 147 | os.write("Host: localhost\n".getBytes()); |
| 148 | os.write("\n".getBytes()); |
| 149 | is = sock.getInputStream(); |
| 150 | bis = new BufferedReader(new InputStreamReader(is)); |
| 151 | String line = bis.readLine(); |
| 152 | if (line != null && line.contains("200")) { |
| 153 | stat.addStatus(TEST_NAME2, stat.FAIL); |
| 154 | } else { |
| 155 | stat.addStatus(TEST_NAME2, stat.PASS); |
| 156 | } |
| 157 | } |
| 158 | finally { |
| 159 | try { |
| 160 | if (os != null) os.close(); |
| 161 | } catch (IOException ex) {} |
| 162 | try { |
| 163 | if (is != null) is.close(); |
| 164 | } catch (IOException ex) {} |
| 165 | try { |
| 166 | if (sock != null) sock.close(); |
| 167 | } catch (IOException ex) {} |
| 168 | try { |
| 169 | if (bis != null) bis.close(); |
| 170 | } catch (IOException ex) {} |
| 171 | } |
| 172 | } |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 173 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 174 | private void invokeValidationTestForColon() throws Exception { |
David Matějček | f4dc06a | 2021-05-17 12:10:57 +0200 | [diff] [blame^] | 175 | |
Vinay Vishal | 5717147 | 2018-09-18 20:22:00 +0530 | [diff] [blame] | 176 | Socket sock = null; |
| 177 | OutputStream os = null; |
| 178 | InputStream is = null; |
| 179 | BufferedReader bis = null; |
| 180 | try { |
| 181 | // Validating the ":" file traversal check |
| 182 | sock = new Socket(host, Integer.valueOf(adminPort)); |
| 183 | os = sock.getOutputStream(); |
| 184 | String get = "GET " + "/resource/file%3a///etc/passwd/ HTTP/1.1\n"; |
| 185 | System.out.println(get); |
| 186 | os.write(get.getBytes()); |
| 187 | os.write("Host: localhost\n".getBytes()); |
| 188 | os.write("\n".getBytes()); |
| 189 | is = sock.getInputStream(); |
| 190 | bis = new BufferedReader(new InputStreamReader(is)); |
| 191 | String line = bis.readLine(); |
| 192 | if (line != null && line.contains("200")) { |
| 193 | stat.addStatus(TEST_NAME3, stat.FAIL); |
| 194 | } else { |
| 195 | stat.addStatus(TEST_NAME3, stat.PASS); |
| 196 | } |
| 197 | } |
| 198 | finally { |
| 199 | try { |
| 200 | if (os != null) os.close(); |
| 201 | } catch (IOException ex) {} |
| 202 | try { |
| 203 | if (is != null) is.close(); |
| 204 | } catch (IOException ex) {} |
| 205 | try { |
| 206 | if (sock != null) sock.close(); |
| 207 | } catch (IOException ex) {} |
| 208 | try { |
| 209 | if (bis != null) bis.close(); |
| 210 | } catch (IOException ex) {} |
| 211 | } |
| 212 | } |
| 213 | } |