EaglerCraft = offline Minecraft

SteveHarmon
Contributor

We have been having issues with EaglerCraft and cannot figure out how to block it. For those who do not know, EaglerCraft is an offline, scaled-down version of Java Minecraft. It is not supported by Mojang, it was developed by some folks who have made it available on Github. Because it is offline and runs locally on a Chromebook, most content filters (we currently use Securly) and device management (we currently use LanSchool) cannot "see" it because no traffic is going on the internet. Teachers have been complaining about this because they cannot see it on LanSchool. The way it works is that the students save the HTML file to their Drive from home (they cannot access the sites that have the file while on campus because it is blocked - but it they use a personal computer with their district credentials then they can save it to their Drive). From there, they share it with their friends. Then the person can run it using the Files app on their Chromebook. So far, nothing I have tried works to block it. I can usually find and remove individual instances of it in Drive if I know who the user is, but it is time consuming to do this, and students can just go home at the end of the day and download it again. Also, if they are savvy enough to change the name of the file, then my search parameters will not work.

Any solutions (or ideas!) that folks have come up for this issue would be greatly appreciated!

3 ACCEPTED SOLUTIONS

VeronicaC
New Contributor

I was able to create the rule after going through the investigation tool which found a few downloads. At least I will be notified if this download increases! I included my set up below.Eaglercraft.jpg

View solution in original post

tvasso
New Contributor II

You can go to Rules in Admin. Create a Rule. See below for how I set it up.Screenshot 2024-03-25 at 10.06.15 AM.png

View solution in original post

SteveHarmon
Contributor

Thanks @tvasso for the idea about using the Investigation Tool. My issue with this was that it is still a manual process and I was hoping to automate it. Your suggestion did spur an idea for me, though. I ended up using GAM to export to a Sheet a list of all of the HTML files in our Student OU. 

gam ou_and_children /Students show filelist query "mimeType contains 'html'" fields id,name,createdDate,lastViewedByUser,explicitlyTrashed,fullFileExtension,lastviewedbyuser,filesize,size,alternatelink todrive tdfileid FILEID tdsheet id:SHEETID tdretaintitle true tdupdatesheet true tdnobrowser true

Then I have a second tab that runs a query on the data:

=query(RawData_AND!A:I,"select * where Col7>10000000 and Col7<20000000",1)

Col7 is the filesize. I found that the only HTML files over 10,000,000 bytes were offline games. I suppose I could remove the top cap of 20,000,000 bytes, but I haven't yet.

Then I used another GAM command to purge these from our Drive:

gam csv gsheet MYEMAIL FILEID FilterByFilesize gam user ~Owner purge drivefile ~id

The "FilterByFilesize" is the name of the tab in the Google sheet.

I put the GAM commands into a BAT file, then run a task scheduler action to run that command daily (at midnight - it does take a LONG time to scan all of the students' files looking for HTML files). On Friday when I ran it manually, there were over 1100 files found - when it ran last night, there were seven files found. After a few months, I might run it weekly instead of daily.

View solution in original post

21 REPLIES 21

NielsBrockmeier
Contributor

Althought a bit drastic, and I'd recommend first trying it on a subset of students if possible. You could try blocking the URL to open local files in the browser. It would, from a first quick try, mainly impact opening PDFs from local  storage. But installing the Adobe Acrobat extension would prevent this, as it opens in the extension which doesn't need a subscription I believe. The URL to block:

file://*

 But it might impact more than just this file, so I'd recommend to not roll this out for everyone at once

This is what I do, but I only block Javascript access on local files to avoid blocking other legitimate files usage. 

John R. Sowash
@jrsowash | Chrmbook.com

Bluecomet
New Contributor

Great question!  If you find a solution I would love to know it!

tvasso
New Contributor II

I set up a Rule in Google Admin. I receive an alert any time activity for Document Type = html occurs on a student chromebook. This at least keeps me aware of the potential game downloading activity. 

Great idea! I will test this out and see if I can use this in some manner!

I've been playing around with this, but I haven't had any luck.  It might be in the way I'm using the rules, can you share any details on Rule type and conditions that worked for you?

tvasso
New Contributor II

You can go to Rules in Admin. Create a Rule. See below for how I set it up.Screenshot 2024-03-25 at 10.06.15 AM.png

robbabiak
New Contributor III

Controversial Take: Is this a Device Management Issue or a Classroom Management Issue?

In some ways I would consider this a bit of both, leaning more heavily towards the classroom management side. The issue is that teachers are trying to use our device management solution (we use LanSchool) but because it does not use the internet a blank screen shows on the tool. If the teacher walks to check it out, the students quickly hide the window or close the window. Because the file URL is so cryptic, the teachers don't know what is happening, but they suspect something is happening which is why they reach out to IT. I keep trying to find a technical solution to this if one exists in order to throw a bone (idiom for trying to help them out) to the teachers!

VeronicaC
New Contributor

I was able to create the rule after going through the investigation tool which found a few downloads. At least I will be notified if this download increases! I included my set up below.Eaglercraft.jpg

Beautiful!

--
https://wheretofind.me/@NoSubstitute

Just be careful with relying on the Title search for Eaglercraft, as the students are savvy enough to change the name of the file. I found some that were named Clever (our single sign-on solution) or named after our math program - they probably thought that the name would show up in the classroom management tool and teachers would assume they were on task. The filesize ended up being the best way to filter things as most regular HTML files are not as large as the offline games.

SteveHarmon
Contributor

Thanks @tvasso for the idea about using the Investigation Tool. My issue with this was that it is still a manual process and I was hoping to automate it. Your suggestion did spur an idea for me, though. I ended up using GAM to export to a Sheet a list of all of the HTML files in our Student OU. 

gam ou_and_children /Students show filelist query "mimeType contains 'html'" fields id,name,createdDate,lastViewedByUser,explicitlyTrashed,fullFileExtension,lastviewedbyuser,filesize,size,alternatelink todrive tdfileid FILEID tdsheet id:SHEETID tdretaintitle true tdupdatesheet true tdnobrowser true

Then I have a second tab that runs a query on the data:

=query(RawData_AND!A:I,"select * where Col7>10000000 and Col7<20000000",1)

Col7 is the filesize. I found that the only HTML files over 10,000,000 bytes were offline games. I suppose I could remove the top cap of 20,000,000 bytes, but I haven't yet.

Then I used another GAM command to purge these from our Drive:

gam csv gsheet MYEMAIL FILEID FilterByFilesize gam user ~Owner purge drivefile ~id

The "FilterByFilesize" is the name of the tab in the Google sheet.

I put the GAM commands into a BAT file, then run a task scheduler action to run that command daily (at midnight - it does take a LONG time to scan all of the students' files looking for HTML files). On Friday when I ran it manually, there were over 1100 files found - when it ran last night, there were seven files found. After a few months, I might run it weekly instead of daily.

Such a great use of GAMADV-XTD3!

--
https://wheretofind.me/@NoSubstitute

Just a follow-up:

I ended up removing the upper-limit on filesize, as there were a bunch of other type of off-line games that were much larger filesizes. I figured that anything above 10000000 was not going to be legitimate!

Also, another forum asked about this and the Sheet I use, so I made this public-facing one: https://docs.google.com/spreadsheets/d/1928-RS5BF4s4kB4rySaiYJhZWYs_BIQt8qZFsnh5Pmw/edit#gid=113899. The first tab has instructions on how to use it. Use it carefully, as you can delete a bunch of stuff on accident if you are not careful!

Jrsowash
Contributor

You can block EaglerCraft and similar offline games by blocking locally run Javascript. I recorded this video to walk you through the steps: https://www.youtube.com/watch?v=2bM1liYruDM

Google help article on blocking local files 

John R. Sowash
@jrsowash | Chrmbook.com

Thanks, John! This worked as advertised in preventing EaglerCraft from running. Unfortunately, it had the side effect of disabling an extension we run called One Two One that prevents students from using other student's Chromebooks. Not sure if we could put the One Two One extension on the allow list - will need to test this another day!

Olger
New Contributor III

We use GATLabs GAT Shield (and GAT+ and Teacher Assist) to keep our students on the straight. GAT Shield is a browser extension and so runs on the device. I run weekly reports listing everything I find on "file:///media/fuse/" and export that to a Gsheet. I then use filters and pivot tables to check for, amongst others, Eaglercraft. If found, that chromebook gets reset from the admin console, wiping their local media. I then trace back where the files were downloaded from and block that website.

I also "follow" (report on) a bunch of known offenders and check their browsing history. THose students now work for me. 😄 They find stuff, I see it, and block it. It's a nice little dance.

I haven't found any mention of it on this forum, but there's a sneaky way students can play games, bypassing lots of content filters. This uses the "about:blank" page in Chrome Interstellar is a well known website. We block this by redirecting about:blank to google.com.au (using GAT Shield). GAT Shield itself also prevents abuse of about:blank.

@SteveHarmon, we have assigned our chromebooks to users (as most probably have) and use GAM to check (running from a Windows server on a 10 min schedule) whether the recent user matches the assigned user. If not, the script disables the user account in Workspace and they have to turn up at the IT Office, where we explain why they can't use someone else's laptop. Student rarely use another laptop now as they know very well what happens.

I can share the Powershell script that we use for this if there's an interest.

 

That GAM + Powershell script sounds cool. Please, do share.

--
https://wheretofind.me/@NoSubstitute

Olger
New Contributor III

So because of how the Windows Task Scheduler works, I always use two batchfiles for scheduled tasks. My naming convention in this case is:

  • checkStudentsRecentusers.cmd
  • checkStudentsRecentusers-scheduledTask.cmd

The problem with the Windows Task scheduler is that once you've created a task that invokes a batchfile, you can't change that batchfile any more. So I create a batchfile for the scheduler that invokes my normal batchfile with a single line (and any required parameters):

c:\scripts\scheduled\checkStudentsRecentusers.cmd diff nopause

My checkStudentsRecentusers.cmd batchfile has the folowing content:

@ECHO OFF
CLS
ECHO ********************************
ECHO ** Check Students Recentusers **
ECHO ********************************

pwsh -ExecutionPolicy Bypass -File c:\scripts\scheduled\ps\checkStudentsRecentusers.ps1 %1
 
if /I "%2" NEQ "NoPause" @Pause

The reason why I need a batchfile is because of the ExecutionPolicy. 

And here's the powershell script I use to check the students:

$action = $args[0]
$file = "c:\csv-output\blockedStudents.csv"
$GAM  = "c:\scripts\gam\gam.exe"

write "File: $file"
write "Action: $action"
$action = "diff"
function writeCSV {
         $timestamp = get-date -format 'dd/MM/yyyy hh:mm tt'
         #write "$index  $($crosSerialNumber),$($crosStatus),$($crosLocation),$($crosAssetID),$($crosUser),$($crosRecentUser),$($crosNotes)"
         add-content $file "$($timestamp),$($crosSerialNumber),$($crosStatus),$($crosLocation),$($crosAssetID),$($crosUser),$($crosRecentUser),$($crosNotes)"
         }

function disableUser {
         if ( $crosRecentUser ) {
              $groups = &$GAM print groups member $crosRecentUser
              $User = Get-ADUser -Filter {Emailaddress -eq $crosRecentUser} | select-object samaccountname -expandproperty samaccountname
              if ( $groups -like "*allstudents@tmc*" ) { 
                   write "Disabling $($crosRecentUser)"
                   writeCSV
                   Disable-ADAccount -Identity $User
                   &$GAM update user $crosRecentUser suspended on
                   &$GAM update cros $crosDeviceID notes "$($crosRecentUser):$today"
                 }
            }
         }

function clearNotes {
         if ( $crosNotes ) { 
            write "Clearing notes on $($crosAssetID) as assigned user and recent user are the same."
            &$GAM update cros $crosDeviceID notes ""
            }
         }

function checkRecentuser {
         write "Checking $($crosAssetID)"
         if ( $crosUser -ne $crosRecentUser ) {
            write "Checking $($crosRecentUser) on $($crosAssetID)"
            if ( -not $crosNotes ) { 
               write "No existing notes"
               disableUser
               } else {
               write "Existing notes, checking"
               $notes = $crosNotes -split ':'
               if ( $notes[1] -lt $today ) {
                  if ( $notes[0] -ne $crosRecentUser ) { 
                     write "Notes was for a previous day"
                     disableUser
                     }
                  }
               }
            } else { clearNotes }
         }

function checkChromebooks {
         $chromebooksY7 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y07"
         $chromebooksY8 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y08"
         $chromebooksY9 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y09"
         $chromebooksY10 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y10"
         $chromebooksY11 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y11"
         $chromebooksY12 = &$GAM print cros fields serialnumber,status,location,assetid,user,recentusers,notes listlimit 1 limit_to_ou "/Devices/Secondary/Y12"
         $chromebooks    = $chromebooksY7 + $chromebooksY8 + $chromebooksY9 + $chromebooksY10 + $chromebooksY11 + $chromebooksY12
         $today = get-date -format yyyyMMdd
         write $chromebooks

         foreach ($chromebook in $chromebooks) { 
                 $index = $chromebooks.indexof($chromebook)
                 $data = $chromebook -split ','

                 if ( $data[0] -eq "deviceId" ) {
                    $indexDeviceID     = [array]::indexof($data,"deviceId")
                    $indexStatus       = [array]::indexof($data,"status")
                    $indexSerialNumber = [array]::indexof($data,"serialNumber")
                    $indexUser         = [array]::indexof($data,"annotatedUser")
                    $indexLocation     = [array]::indexof($data,"annotatedLocation")
                    $indexAssetID      = [array]::indexof($data,"annotatedAssetId")
                    $indexRecentuser   = [array]::indexof($data,"recentUsers.email")
                    $indexNotes        = [array]::indexof($data,"notes")
                    continue
                    }

                 $crosDeviceID     = $data[$indexDeviceID]
                 $crosStatus       = $data[$indexStatus]
                 $crosSerialNumber = $data[$indexSerialNumber]
                 $crosUser         = $data[$indexUser]
                 $crosLocation     = $data[$indexLocation]
                 $crosAssetID      = $data[$indexAssetID]
                 $crosRecentUser   = $data[$indexRecentuser]
                 $crosNotes        = $data[$indexNotes]
                 if ( $index -ne 0 ) { 
                    if ( $crosStatus -eq 'ACTIVE' ) {
                       if ( $action -eq "diff" ) { 
                        checkRecentuser } 
                        else { writeCSV }
                       }
                    }
                 }
         }


checkChromebooks

We have our students and chromebooks separated in OU's per year. Devices live in the /Devices/Primary/Y* or /Devices/Secondary/Y* OU's, students live in the /Students/Primary/Y* or /Students/Secondary/Y* OU's.  We only check our Secondary (highschool) student chromebooks for mismatching recentusers.

checkChromebooks is the main function, it basically retrieves all chromebooks for each year  in arrays and then builds one large array. Doing this helps with debugging.
Then the function parses each individual chromebook record in the array and checks the recentuser, and if the recentuser is different from the assigned user, it suspends the user account and logs this in a csv file (set in $file, you'll have to change that accordingly).
The same goes for the $GAM variable which you'll need to set to the location of gam.exe.
Once a user is disabled, the notefield is set which ensures the script doesn't check this user again on the same day. That way we don't have to manually clear notes and we keep a little record in the user account.

I can't remember what other actions I wanted to do, the script is currently hardcoded to "diff", which checks if the recentuser is different. We've been running this script for a few years now.

Because students know they'll get locked out, very few try to use someone elses laptop.

Thank you! Also for explaining what the script does.

I always try to include comments in my code, so others can understand and learn (and I can remember! 😂).

--
https://wheretofind.me/@NoSubstitute