How can I render a built-in Gutenberg block with InnerBlocks outside of the block editor?

It was a long and winding road that led me to a working solution, which doesn’t resemble my above attempts very closely at all. In short: instead of importing the Save component by itself, you run the registration functions from the root JS file of the blocks, and then use createBlock and serialize. The full solution for a Quote block with a Paragraph inner block in Storybook follows:

import { RawHTML } from '@wordpress/element';
import { createBlock, serialize } from '@wordpress/blocks';

// Core blocks come with handy init functions that handle all registration and metadata tasks for you.
import { init as paragraphInit } from '@wordpress/block-library/build-module/paragraph';
import { init as quoteInit }  from '@wordpress/block-library/build-module/quote';

// Run ’em!
paragraphInit();
quoteInit();

const Template = args => {
  // createBlock creates a block given the block name, attributes, and optional InnerBlocks.
  const block = createBlock(
    'core/quote',
    args.attributes,
    args.innerBlocks,
  );

  // Now we turn our parsed block into HTML.
  const serializedBlock = serialize(block);

  // “Unsafely” output our serialized block.
  return (
    <RawHTML>
      {serializedBlock}
    </RawHTML>
  );
};

export const Blockquote = Template.bind({});

Blockquote.args = {
  attributes: {
    citation: 'Time Magazine, August 2027',
    value: 'Something',
  },
  innerBlocks: [
    // Provide the InnerBlocks without serializing them.
    createBlock(
      'core/paragraph',
      {
        content: 'Lorem ipsum dolor <em>sit amet</em>',
      }
    )
  ]
};

export default {
  title: 'Default/Blockquote',
  argTypes: {
    attributes: {
      control: 'object'
    },
    innerBlocks: {
      control: 'object'
    }
  },
  parameters: {
    layout: 'padded',
  },
};