Catagory: web
Difficulty: Medium
Author: todo#7331
Whilst performing a security assessment for a company, you notice they have a innocuous service called ezmail which allows employees to leave messages for each other. You reckon you can use this service to get the userPassword
of the admin
account for the whole organization.
Flag format: DUCTF{[a-z0-9_]+}
case sensitive
Largely a blind ldap injection challenge with a pinch of api recon (i.e. reading the docs). Challenge involves reading leaking userPassword
fields for ldap users in a "leave a message" application.
Players can leave messages for users by specifying their ldap common names. The lookup done to map common name -> uuid is injectable, but asynchronus to the request. Players can build a oracle by sending a message containing a ldap injected payload. If the payload results in a value it will be reflected in the "recipients" field of the message when the message is looked up by uuid, otherwise it will be missing.
Medium challenge as most players won't have much experience with ldap, and there are a number of gotcha's that need to be understood.
a solve script can be found in ./solve
- Players notice that the challenge is ldap - this is hinted at in the flavour text, and the world ldap is present in the docs.
- Players notice that inputting special characters (esp
)
) as the name of a recipient will result in that recipient not appearing in therecipients
field of the sent message.- e.g. Sending a message with
an_ok_name
as well as a invalid name)
...POST /message {"recipients":["an_ok_name",")"], ...} -> some_message_id
- ... will result in
)
disappearing from the recipients list when the message is fetchedGET /message/some_message_id -> {"recipients":["an_ok_name"]}
- e.g. Sending a message with
- Players notice that putting a ldap identity (e.g.
someuser)(cn=*
) as a recipient passes. This in combination with the previous fact reveals a LDAP injection. - The flavour text mentions to get the
userPassword
field. This can be tested withsomeuser)(userPassword=*
) - Players do some research on ldap and learn that the
userPassword
field uses a octet string so wildcard matches don't work, there are howeverstrcmp
-esque operators. - There is a
octetStringOrderingMatch
operator on octet strings that will return results if our input is "larger" than the stored value. - Therefore players are able to enumerate the
userPassword
one character at a time.- If the player's guess is less than or equal to the
userPassword
the recipient will be missing - If the player's guess is greater than the
userPassword
, then the recipient will be present. - The "highest" value that does not appear is hence a character in the password
- If the player's guess is less than or equal to the
- Players notice they can also batch requests to perform 8 at a time.
- Using this observation its possible to construct a blind search for the password either linearly or using a binary (or octonary) search.
docker-compose up
Probably can share between players if we pray to the uuid gods hard enough. 🤷