List<string> list1 = new List<string>(){ "Ugly", "Pretty"};
List<string> list2 = new List<string>(){ "Dogs", "Carts", "Pigs"};
List<string> list3 = new List<string>(){ "Rock", "Suck"};
var result = from s1 in list1
             from s2 in list2
             from s3 in list3
             select new[] { s1, s2, s3 };
foreach (var item in result)
{
    Console.WriteLine(String.Join(",", item));
}
If you are looking for a more general solution, not only for 3 lists you may try Eric Lippert's solution
foreach (var item in new[] { list1, list2, list3 }.CartesianProduct())
{
    Console.WriteLine(String.Join(",", item));
}
public static partial class MyExtensions
{
    // Eric Lippert’s Blog
    // Computing a Cartesian Product with LINQ
    // http://blogs.msdn.com/b/ericlippert/archive/2010/06/28/computing-a-cartesian-product-with-linq.aspx
    public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
    {
        // base case: 
        IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() };
        foreach (var sequence in sequences)
        {
            var s = sequence; // don't close over the loop variable 
            // recursive case: use SelectMany to build the new product out of the old one 
            result =
                from seq in result
                from item in s
                select seq.Concat(new[] { item });
        }
        return result;
    }
}