Seems like MapReduce could be one way to solve this; unfortunately it wouldn't give an instant result if it is done on the fly.
Just thinking through it you could, in the map phase, count the number of times a pair of students end up in the same class. During the reduce phase you could sum the pairs and write out (emit) the pairs that had a sum of 2 or more. This approach could be used to pre-generate an index (as suggested earlier) that indicates the pairs of students with "x" courses in common. The key to such an index could be something along the lines of "X/Student1_Key/Student2_Key", where X is the number of courses they have in common and. A range scan over the index (e.g., X>=2) would give you your answer. Given HBase's native integration with MapReduce a solution along these lines should be straightforward.
Also, following the BigTable model, you wouldn't even need to create two tables. Just precede each record key with a "kind" such as Course: or Student:. Since the rows are ordered lexicographically they are easily scanned by kind. Populate (or generate) the columns needed to support properties for each kind. Since HBase supports highly sparse tables this works well. See this excellent presentation on selecting keys and developing indices with BigTable: http://www.google.com/events/io/2009/sessions/BuildingScalableComplexApps.html. This presentation really helped me understand how to store things in databases such as HBase for efficient retrieval.
But back to the original question, it seems that when working with HBase you really have to know how your data is to be used so appropriate indices can be developed beforehand to get quick answers. It doesn't appear that random ad-hoc queries will always work out with this model.
Anyway, I'm also new to this so seeing problems like these and possible solutions helps!