Noah Therriault

ntherriault [at] umass [dot] edu

me
attending class from my bed
9/5/2025

Background

I’m currently in my second year of college, and all of my computer science classes have been using a new attendance system called ClassQuestion. As opposed to my first-year classes, which either had no attendance requirement or the impenetrable defense of attendance codes in the slides, this new system seemed more susceptible to exploitation.

ClassQuestion

The site itself is quite simple. The professor displays a multiple-choice question with four possible answers (A, B, C, or D), and students navigate to ClassQuestion to submit their answer. The correct answer is revealed, and a graph is displayed showing how students answered. Attendance is measured by participation.

The site is meant to be a free replacement to the loathed iClicker (iykyk), and accomplishes this goal with a large asterisk.

An Obvious Issue

While iClickers operate using radio frequencies (therefore enforcing proximity to the class), ClassQuestion is completely online meaning that you can answer questions from anywhere and “attend” the class.

Many students have realized this, and lectures with ~25 people at most will often have 60+ submissions on ClassQuestion. However, these students are doing it manually, that is, logging on to the site and waiting for questions to pop up. If you have to monitor your computer for a question to arrive, are you really not fully attending?

In order to reach the full potential of skipping class while also “attending,” I decided to fully automate the process of answering questions.

Automation

The first thing I looked at was authentication. This was, thankfully, quite simple.

When logging in, the website sends a POST request to /login/logon_student with the JSON

{
   "p_number": null,
   "email" : "foo@example.com",
   "password": "password1"
}

The corresponding response contains cookies that are necessary for authentication on all of the other endpoints.

In ClassQuestion, classes are identified by a 5-letter string known as a roomcode. In order to fetch a list of active roomcodes, the website sends a GET request to /get_student_rooms

Replicating this request with the previously obtained cookies, we get the response

{
   "roomcode" : "ABCDEF",
   "classname" : "CS 50"
},
{
   ...
}

containing all of the active classes.

When entering a class, the website constantly sends GET requests to the endpoint /poll/[roomcode]. Using the roomcodes we previously obtained, we can

The responses to these requests contain the JSON

"data" : {
   "msg": "success",
   "islive" : 0
}

“islive” tells us whether there is currently a live question.

When “islive” is 1, the JSON contains the following extra fields

"data" : {
   "msg": "success",
   "islive" : 1,
   "qdata" : {
       "archid" : 123,
       "cora" : 0,
       ...
   }

}

Notice, not only are we sent essential question data, but also the correct answer (cora). So, while skipping class, you can also look super smart to your professor!

The submission logic was by far the hardest part to get right, when in class I always use my phone to submit the answers, and therefore, I wasn’t able to intercept the request. I worked on this on the weekend and wasn’t willing to wait for class on Monday to finish it.

Therefore, I went into the site’s JavaScript.

It was not minified or obfuscated in any form, so it wasn’t too bad. After searching for a while, I found the following function

//function to submit student answer
function submitanswer(answer, archiveid) {

   ...

   var dataArray = {
       "answer": answer,
       "archid": archiveid,
       "roomcode": room_code
   };

   var dataJSON = JSON.stringify(dataArray);
   
   ...
           
   submitAnsAjax1 = $.ajax({
       type: "POST",
       url: studentans_route,
       data: dataJSON,
       dataType: 'json',
       success: function (response) {

           $('#answerloader').hide();
           window.scrollTo(0, 0);
           submitted();

       },
       error: function (error) {
           $('#answerloader').hide();
           window.scrollTo(0, 0);
           ShowAnsSubmitError();
           console.log('Error:', error);
       }
   }); // end ajax

   var dataArray = {
       "answer": answer
   };

   submitAnsAjax2 = $.ajax({
       type: "POST",
       url: post_redis_ans_route,
       data: dataJSON,
       dataType: 'json',
       success: function (response) {

       },
       error: function (error) {

           console.log('Error:', error);
       }

   }); // end ajax

   ...
}

By replicating these requests in a programming language of your choice, we accomplished our goal: full automation!

Conclusion

The system could be changed to make this method and the earlier described manual method infeasible. Simply make the answer to the question be a passcode that only someone in person would know and don’t tell the client the correct answer when sending question data ;).

Although I do not intend to use it for myself (I enjoy and attend all my classes), it was an interesting project, and a good use of a weekend.