{"id":14266,"date":"2017-07-28T18:45:23","date_gmt":"2017-07-28T16:45:23","guid":{"rendered":"https:\/\/codisec.com\/?p=14266"},"modified":"2023-03-22T16:29:57","modified_gmt":"2023-03-22T15:29:57","slug":"ctfzone-2017-riches-wings","status":"publish","type":"post","link":"https:\/\/codisec.com\/ctfzone-2017-riches-wings\/","title":{"rendered":"CTFZone 2017: Riches have wings"},"content":{"rendered":"

CTF: CTFZONE 2017
\nPoints: 921
\nCategory: Web, PPC<\/p>\n

Description<\/h2>\n

We\u2019ve heard that your candidate is experiencing financial difficulties during his election campaign. If media finds out, it will be a disaster. You have one day to fix this problem. Otherwise we are ruined. Remember, you shall leave no trace<\/a>…<\/p><\/blockquote>\n

On the second day we also got a hint:<\/p>\n

\"\"<\/p>\n

First part: web<\/h2>\n

At the beginning when we open provided link, we get a standard sign in \/ sign up form (with captcha, so we can’t create users automatically) and nothing else.<\/p>\n

\"\"<\/p>\n

Firstly, let’s sign up with username codisec_writeup<\/tt> and look what’s inside the service.<\/p>\n

\"\"<\/p>\n

Well, not too much… The only thing we can do is logging out, the rest of the links lead to the current page.<\/p>\n

But while viewing the HTTP headers, we notice that a cookie set by this page is quite strange:
\n\"62a63956496ad24338340c0e64c45c621eca9fa0b9afb4069c58c985d9888a12\"<\/code>.
\nIt has quotes around the text, so maybe some database query is just concatenated with it.<\/p>\n

Now it’s time to make use of our hint: that leaf is MongoDB<\/a> logo (we can check it using Google Images).<\/p>\n

Let’s assume that database query looks something like this:<\/p>\n

{\r\n\t\"some_session_id_field\": <COOKIE CONTENT>\r\n}\r\n<\/pre>\n

Let’s try some injection. We set our cookie to: {\"$exists\": true}<\/code>. Then the database query would become:<\/p>\n

{\r\n\t\"some_session_id_field\": {\"$exists\": true}\r\n}\r\n<\/pre>\n

which means just ‘attribute some_session_id_field<\/tt> exists’, so it matches to all sessions (it does not use any filters).
\nThat cookie gives us certain session, which means that injections work:
\n\"\"<\/p>\n

We’ve actually known that this field exists, but we can test other ones!
\nFor example, setting {\"$exists\": true}, \"username\": {\"$exists\": true}<\/code> as cookie gives us:<\/p>\n

{\r\n\t\"some_session_id_field\": {\"$exists\": true},\r\n\t\"username\": {\"$exists\": true}\r\n}\r\n<\/pre>\n

If provided attribute exists, we will get some session. Otherwise we will get blank page, which means that something went wrong.<\/p>\n

After a little experimenting we realize that field named login<\/tt> exists.<\/p>\n

Let’s try setting login to codisec_writeup<\/tt>:
\n{\"$exists\": true}, \"login\": \"codisec_writeup\"<\/code><\/p>\n

It works.<\/p>\n

So why don’t we set admin<\/tt> as login?
\n{\"$exists\": true}, \"login\": \"admin\"<\/code><\/p>\n

But this doesn’t work.<\/p>\n

Maybe something similar, like administrator<\/tt>, admin2017<\/tt>, my_super_admin<\/tt>?<\/p>\n

Let’s use some regular expressions to filter which logins are in database:
\n{\"$exists\": true}, \"login\":{\"$regex\": \"admin\"}<\/code><\/p>\n

{\r\n\t\"some_session_id_field\": {\"$exists\": true},\r\n\t\"login\": {\"$regex\": \"admin\"}\r\n}\r\n<\/pre>\n

\"\"
\nWhat’s going on? user2<\/tt> does not contain admin<\/tt> as a substring!<\/p>\n

With {\"$exists\": true}, \"login\": {\"$regex\": \"^co[abcd]i.ec_writeup$\"}<\/code> we can ensure that regular expressions work properly.<\/p>\n

The tricky part is to realize that server is protected by some kind of WAF<\/a> that filters out admin<\/tt> from cookie value before query execution!
\nNow we can easily bypass it using {\"$exists\": true}, \"login\": {\"$regex\": \"^ad[m]in$\"}<\/code>.<\/p>\n

Another way is to set {\"$exists\": true}, \"login\": \"admadminin\"<\/code>. Probably it works because some common replace function is used for filtering, which for admadminin<\/tt> results with admin<\/tt>.<\/p>\n

Now we have our longed-for admin privileges.
\n\"\"
\nHere we can do one thing more: sending invitations to arbitrary users.<\/p>\n

Second part: fraud<\/h2>\n

After activating codisec_writeup<\/tt> and relogging to it, we can see two new options:<\/p>\n