Just for sports
a solution without explicit conditionals or predicates
(i.e., without any if keywords):
from itertools import chain, repeat, permutations
from copy import deepcopy
def shuffle(*strings):
    # Treat the strings as pools from which to draw elements in order.
    # Convert the strings to lists, so that drawn items can be removed:
    pools = (list(string) for string in strings)
    # From each pool, we have to draw as many times as it has items:
    pools_to_draw_from = chain.from_iterable(
        repeat(pool, len(pool)) for pool in pools
    )
    # Because itertools.permutations treats elements as unique based on their
    # position, not on their value and because pools_to_draw_from has repeated
    # repeated items, we would get repeated permutations, if we would not
    # filter them out with `unique`.
    possible_drawing_orders = unique(permutations(pools_to_draw_from))
    # For each drawing order, we want to draw (and thus remove) items from our
    # pools. Subsequent draws within the same drawing order should get the
    # respective next item in the pool, i.e., see the modified pool. But we don't
    # want the pools to be exhausted after processing the first drawing ordering.
    #
    # Deepcopy preserves internal repetition and thus does exactly what we need.
    possible_drawing_orders = (deepcopy(pdo) for pdo in possible_drawing_orders)
    # Draw from the pools for each possible order,
    # build strings and return them in a list:
    return [''.join(_draw(p)) for p in possible_drawing_orders]
def _draw(drawing_order):
    return (pool_to_draw_from.pop(0) for pool_to_draw_from in drawing_order)
We need a helper function for this:
from operator import itemgetter
from itertools import groupby
def unique(iterable, key=None):
    # Other than unique_everseen from
    # https://docs.python.org/3/library/itertools.html#itertools-recipes, this
    # works for iterables of non-hashable elements, too.
    return unique_justseen(sorted(iterable, key=key), key)
def unique_justseen(iterable, key=None):
    """
    List unique elements, preserving order. Remember only the element just seen.
    """
    # from https://docs.python.org/3/library/itertools.html#itertools-recipes
    return map(next, map(itemgetter(1), groupby(iterable, key)))
If the number of non-unique permutations is large, this is probably rather inefficient, due to the call to sorted. For alternatives to obtain unique permutations of non-unique values, see permutations with unique values.
TL;DR?
No problem. We can boil this approach down to this abomination:
from itertools import chain, repeat, permutations
from copy import deepcopy
def shuffle(*strings):
    return list({''.join(l.pop(0) for l in deepcopy(p)) for p in permutations(chain.from_iterable(repeat(list(s), len(s)) for s in strings))})
(Using a set comprehension on the result instead of ensuring uniqueness earlier.)