It's something I'd wanted to implement for a while and I got it working yesterday. It wasn't too bad. I believe there's an example of using the OVRCustomSkeleton script in the sample framework.
So in my implementation I have a prefab with OVRHand, OVRCustomSkeleton and my "HandController" script that instantiates the rendered hand and updates the positions of the bones of the rendered hand in LateUpdate.
In the Start of the HandController I get the Bones from the OVRCustomSkeleton (may have to wait a frame before the bone Count != 0) and match each bone transform from the skeleton to a transform in the instantiated hand (an array of (Transform,Transform) tuples).
Then in LateUpdate I iterate over that array and set the localPosition and localRotation of the rendered hand transform to the localPosition and localRotation of the skeleton transform.
I recommend using OVRHand.IsDataHighConfidence instead of OVRHand.IsTracked to decided whether to update the transforms, because the last few frames before tracking is lost can send the hand to completely random positions/poses.