Unfortunately there is no 'IsCustom' field or anything similar on the Profile object.
The only workaround that I know of is to compare the CreatedDate
of your Profiles to the CreatedDate
of you org.
Organization org = [SELECT Id , CreatedDate FROM Organization];
List<Profile> customProfiles =
[
SELECT Id, Name, CreatedDate
FROM Profile
WHERE CreatedDate > :org.CreatedDate
];
This is not a perfect solution as in one of my orgs this still bring back the 'Chatter Free User', 'Chatter Moderator User', 'Chatter External User' and 'Guest License User'. You can filter these values out, although I'm not sure if the below will work in non-English language orgs.
Organization org = [SELECT Id , CreatedDate FROM Organization];
List<Profile> customProfiles =
[
SELECT Id, Name, CreatedDate
FROM Profile
WHERE CreatedDate > :org.CreatedDate
AND Name NOT IN('Chatter Free User', 'Chatter Moderator User', 'Chatter External User', 'Guest License User')
];