├── README.md ├── configurator.py ├── csel.cfg ├── iguana.png ├── install.sh ├── logo.png └── payload /README.md: -------------------------------------------------------------------------------- 1 | # CSEL 2 | ## Cyberpatriot Scoring Engine: Linux 3 | 4 | CSEL is a scoring engine written in bash for scoring Linux CyberPatriot images. It is configured by adding scoring options into the csel.cfg and running the install file. It now includes a web page Score Report. It works (to varying degrees) with Ubuntu 14.04 and 16.04. 5 | 6 | ## Important Update 7 | CSEL has been rewritten in python as PySEL. Try it out here: [PySEL Repo](https://github.com/FWSquatch/pysel) 8 | 9 | ## Features 10 | CSEL is still a baby and it's rough around the edges, but so far it can score the following events: 11 | - Deleting "bad" users 12 | - Creating new "good" users 13 | - Changing passwords on accounts 14 | - Removing users from the admininstrator group 15 | - Creating groups 16 | - Securing /etc/sudoers file 17 | - Disabling guest login 18 | - Disabling autologin 19 | - Disabling usernames on the login page 20 | - Setting the minimum password age 21 | - Setting the maximum password age 22 | - Setting the maximum number of login tries 23 | - Setting password history value 24 | - Setting password length 25 | - Installing "good" programs 26 | - Uninstalling "bad" programs 27 | - Deleting prohibited files 28 | - Removing backdoors (malicious services) 29 | - Enabling the firewall 30 | - Securing ssh 31 | - Configuring the hosts files 32 | - Updating the kernel 33 | - Removing things from user crontabs 34 | - Updating clamav virus definitions 35 | - Removing things from startup 36 | - Answering the forensics question correctly 37 | - Changing update options 38 | - Adding or uncommenting lines from config files 39 | - Deleting or commenting lines from config files 40 | 41 | CSEL can also take away points for: 42 | - Deleting "good" users 43 | 44 | CSEL can be run with "silent misses" which simulates a CyberPatriot round where you have no idea where the points are until you earn them. It can also be run with the silent misses turned off which is helpful when you are debugging or when you have very inexperienced students who might benefit from the help. This mode gives you a general idea where the points are missing. 45 | 46 | ## How to install 47 | 1. Set up your image and put your vulnerabilities in place. 48 | 2. Install the following prerequisites: git and python-tk. 49 | 3. Clone into CSEL by typing: sudo git clone https://github.com/FWSquatch/CSEL.git 50 | 4. Run python configurator.py to set up the config file. 51 | 5. Run the installer by typing `sudo ./install` in the CSEL directory. 52 | 6. After you are satisfied that it is working how you want, you can delete the CSEL directory. 53 | 54 | **Important Note**: Your students _will_ be able to see the vulnerabilities if you leave the CSEL folder behind or if they cat the executable file that is created in /usr/local/bin/. I tell my students where the file is and that they should stay away from it. It is practice, after all. 55 | -------------------------------------------------------------------------------- /configurator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from Tkinter import * 4 | 5 | class ForenQuest: 6 | def __init__(self,name,question,answer,points,enabled): 7 | self.name = name 8 | self.question = question 9 | self.answer = answer 10 | self.points = points 11 | self.enabled = enabled 12 | 13 | fq01 = ForenQuest("Question1.txt","Here is my question...","myanswer","0","0") 14 | fq02 = ForenQuest("Question2.txt","Here is my question...","myanswer","0","0") 15 | 16 | class Vuln: 17 | def __init__(self,name,points,enabled,keywords,hit,miss,tip): 18 | self.name = name #What is the vulnerability called? 19 | self.points = points #How many points is it worth? 20 | self.enabled = enabled #Is the item being scored? 21 | self.kw = keywords #Keywords to look for when scoring (Not used on all) 22 | self.hm = hit #Message to display on a hit (Not implemented on all yet) 23 | self.mm = miss #Message to display on a miss (Not implemented on all yet) 24 | self.tip = tip #Explanation of the item 25 | 26 | v01 = Vuln("disableGuest","0","0","","","","Is the guest disabled in lightdm?") 27 | v02 = Vuln("disableAutoLogin","0","0","","","","Is there an auto logged in user in lightdm?") 28 | v03 = Vuln("disableUserGreeter","0","0","","","","Disable the user greeter in lightdm") 29 | v04 = Vuln("disableSshRootLogin","0","0","","","","'PermitRootLogin no' exists in sshd_config") 30 | v05 = Vuln("checkFirewall","0","0","","","","Is ufw enabled?") 31 | v06 = Vuln("checkKernel","0","0","","","","Has kernel been updated?") 32 | v07 = Vuln("avUpdated","0","0","","","","Has clamav freshclam been run?") 33 | v08 = Vuln("silentMiss","0","0","","","","Check this box to hide missed items\n(Similar to competition)") 34 | v50 = Vuln("goodUser","0","0","","","","Lose points for removing this user (use negative number)") 35 | v51 = Vuln("badUser","0","0","","","","Remove these users to score") 36 | v52 = Vuln("goodProgram","0","0","","","","Score points by installing these programs") 37 | v53 = Vuln("badProgram","0","0","","","","Score points by removing these programs") 38 | v54 = Vuln("checkStartup","0","0","","","","Check rc.local for a specific string (type string in 'keywords')") 39 | v55 = Vuln("checkHosts","0","0","","","","Check /etc/hosts for a specific string (type string in 'keywords')") 40 | v56 = Vuln("badCron","0","0","","","","Check the root cron for a specific string (type string in 'keywords')") 41 | v57 = Vuln("badFile","0","0","","","","Score points for deleting this file") 42 | v58 = Vuln("minPassAge","0","0","","","","Value of min password age to score (login.defs)") 43 | v59 = Vuln("maxPassAge","0","0","","","","Value of max password age to score (login.defs)") 44 | v60 = Vuln("maxLoginTries","0","0","","","","Value of max login retries to score (login.defs)") 45 | v61 = Vuln("checkPassLength","0","0","","","","Value min pw length (pam.d/common-password)") 46 | v62 = Vuln("removeAdmin","0","0","","","","Remove these users from the sudo group") 47 | v63 = Vuln("newUser","0","0","","","","This user must be created") 48 | v64 = Vuln("groupExists","0","0","","","","This group must be created") 49 | v65 = Vuln("serviceRunning","0","0","","","","Service that needs to be stopped") 50 | v66 = Vuln("changePassword","0","0","","","","User who must change password") 51 | v67 = Vuln("secureSudoers","0","0","","","","Words to be removed from /etc/sudoers file") 52 | v81 = Vuln("fileContainsText1","0","0","","","","Command has 4 parts: 1-file location, 2-text to add or uncomment, 3-points to award, 4-Success message for score report") 53 | v82 = Vuln("fileContainsText2","0","0","","","","Command has 4 parts: 1-file location, 2-text to add or uncomment, 3-points to award, 4-Success message for score report") 54 | v83 = Vuln("fileNoLongerContains1","0","0","","","","Command has 4 parts: 1-file location, 2-text to delete or comment, 3-points to award, 4-Success message for score report") 55 | v84 = Vuln("fileNoLongerContains2","0","0","","","","Command has 4 parts: 1-file location, 2-text to delete or comment, 3-points to award, 4-Success message for score report") 56 | v85 = Vuln("userInGroup","0","0","","","","Command has 3 parts: 1-group in question, 2-user that must be in group, 3-points to award") 57 | 58 | vulns = [v01,v02,v03,v04,v05,v06,v07,v08,v50,v51,v52,v53,v54,v55,v56,v57,v58,v59,v60,v61,v62,v63,v64,v65,v66,v67,v81,v82,v83,v84,v85] 59 | 60 | def writeToConfig(name,points,enabled,keywords): 61 | f = open('csel.cfg','a') 62 | if enabled == 1: 63 | line1 = name+'=(y)\n' 64 | line2 = name+'Value=('+str(points)+')\n' 65 | #If there are some keywords, sub them in for the 'y' 66 | if keywords != '': 67 | line1 = name+'=('+str(keywords)+')\n' 68 | f.write(line1) 69 | f.write(line2) 70 | 71 | #Create the forensics questions and add answers to csel.cfg 72 | def createForQ(): 73 | qHeader='This is a forensics question. Answer it below\n------------------------\n' 74 | qFooter='\n\nANSWER: ' 75 | f = open('csel.cfg','a') 76 | line1a = 'forensicsPath1=('+str(usrDsktp.get())+'Question1.txt)\n' 77 | line1b = 'forensicsAnswer1=('+fqans01.get()+')\n' 78 | line1c = 'checkForensicsQuestion1Value=('+str(fqpts01.get())+')\n' 79 | line2a = 'forensicsPath2=('+str(usrDsktp.get())+'Question2.txt)\n' 80 | line2b = 'forensicsAnswer2=('+fqans02.get()+')\n' 81 | line2c = 'checkForensicsQuestion2Value=('+str(fqpts02.get())+')\n' 82 | if fqcb01.get() != 0: 83 | for line in (line1a,line1b,line1c): 84 | f.write(line) 85 | g = open((str(usrDsktp.get())+'Question1.txt'),'w+') 86 | g.write(qHeader+fquest01.get()+qFooter) 87 | g.close() 88 | if fqcb02.get() != 0: 89 | for line in (line2a,line2b,line2c): 90 | f.write(line) 91 | h = open((str(usrDsktp.get())+'Question2.txt'),'w+') 92 | h.write(qHeader+fquest02.get()+qFooter) 93 | h.close() 94 | f.close() 95 | 96 | #What happens when you click Submit? 97 | def submitCallback(): 98 | #We wanna use those fancy variable lists 99 | global checkBoxes 100 | global vulns 101 | global pointVal 102 | global keyWords 103 | f = open('csel.cfg','a') 104 | for vuln,checkEn,score,key in zip(vulns,checkBoxes,pointVal,keyWords): 105 | vuln.enabled = checkEn.get() 106 | vuln.points = score.get() 107 | vuln.kw = key.get() 108 | writeToConfig(vuln.name,vuln.points,vuln.enabled,vuln.kw) 109 | configFooter="index=("+usrDsktp.get()+"ScoreReport.html)\n#These values will change during install\nimageScore=0\nposPoints=0\nrelease=\"\"\ninitialKernel=(%KERNEL%)\ninstallDate=(%INSTALLDATE%)\n" 110 | f.write(configFooter) 111 | f.close() 112 | 113 | 114 | def updateScoreLoc(): 115 | location.config(text=usrDsktp.get()) 116 | 117 | f = open('csel.cfg','w+') 118 | configHeader="#!/bin/bash\n#This config file was generated by configurator.py\n\n" 119 | 120 | f.write(configHeader) 121 | f.close() 122 | #######Tkinter Time!!!############### 123 | 124 | root = Tk() 125 | #Initialize a crap-ton of TK vars. Can you find a more elegant way? 126 | #Forensic Question stuff 127 | usrDsktp = StringVar() 128 | fqcb01 = IntVar() 129 | fqpts01 = IntVar() 130 | fquest01 = StringVar() 131 | fqans01 = StringVar() 132 | fqcb02 = IntVar() 133 | fqpts02 = IntVar() 134 | fquest02 = StringVar() 135 | fqans02 = StringVar() 136 | 137 | #Checkboxes to enable or disable an item 138 | cb01 = IntVar() 139 | cb02 = IntVar() 140 | cb03 = IntVar() 141 | cb04 = IntVar() 142 | cb05 = IntVar() 143 | cb06 = IntVar() 144 | cb07 = IntVar() 145 | cb08 = IntVar() 146 | cb09 = IntVar() 147 | cb10 = IntVar() 148 | cb50 = IntVar() 149 | cb51 = IntVar() 150 | cb52 = IntVar() 151 | cb53 = IntVar() 152 | cb54 = IntVar() 153 | cb55 = IntVar() 154 | cb56 = IntVar() 155 | cb57 = IntVar() 156 | cb58 = IntVar() 157 | cb59 = IntVar() 158 | cb60 = IntVar() 159 | cb61 = IntVar() 160 | cb62 = IntVar() 161 | cb63 = IntVar() 162 | cb64 = IntVar() 163 | cb65 = IntVar() 164 | cb66 = IntVar() 165 | cb67 = IntVar() 166 | cb81 = IntVar() 167 | cb82 = IntVar() 168 | cb83 = IntVar() 169 | cb84 = IntVar() 170 | cb85 = IntVar() 171 | checkBoxes = [cb01,cb02,cb03,cb04,cb05,cb06,cb07,cb08,cb50,cb51,cb52,cb53,cb54,cb55,cb56,cb57,cb58,cb59,cb60,cb61,cb62,cb63,cb64,cb65,cb66,cb67,cb81,cb82,cb83,cb84,cb85] 172 | 173 | #Point values for each item 174 | pts01 = IntVar() 175 | pts02 = IntVar() 176 | pts03 = IntVar() 177 | pts04 = IntVar() 178 | pts05 = IntVar() 179 | pts06 = IntVar() 180 | pts07 = IntVar() 181 | pts08 = IntVar() 182 | pts50 = IntVar() 183 | pts51 = IntVar() 184 | pts52 = IntVar() 185 | pts53 = IntVar() 186 | pts54 = IntVar() 187 | pts55 = IntVar() 188 | pts56 = IntVar() 189 | pts57 = IntVar() 190 | pts58 = IntVar() 191 | pts59 = IntVar() 192 | pts60 = IntVar() 193 | pts61 = IntVar() 194 | pts62 = IntVar() 195 | pts63 = IntVar() 196 | pts64 = IntVar() 197 | pts65 = IntVar() 198 | pts66 = IntVar() 199 | pts67 = IntVar() 200 | pts81 = IntVar() 201 | pts82 = IntVar() 202 | pts83 = IntVar() 203 | pts84 = IntVar() 204 | pts85 = IntVar() 205 | pointVal = [pts01,pts02,pts03,pts04,pts05,pts06,pts07,pts08,pts50,pts51,pts52,pts53,pts54,pts55,pts56,pts57,pts58,pts59,pts60,pts61,pts62,pts63,pts64,pts65,pts66,pts67,pts81,pts82,pts83,pts84,pts85] 206 | 207 | #These are for the keywords that some of the items take (goodUser, badProgram, etc) 208 | kw01 = StringVar() 209 | kw02 = StringVar() 210 | kw03 = StringVar() 211 | kw04 = StringVar() 212 | kw05 = StringVar() 213 | kw06 = StringVar() 214 | kw07 = StringVar() 215 | kw08 = StringVar() 216 | kw50 = StringVar() 217 | kw51 = StringVar() 218 | kw52 = StringVar() 219 | kw53 = StringVar() 220 | kw54 = StringVar() 221 | kw55 = StringVar() 222 | kw56 = StringVar() 223 | kw57 = StringVar() 224 | kw58 = StringVar() 225 | kw59 = StringVar() 226 | kw60 = StringVar() 227 | kw61 = StringVar() 228 | kw62 = StringVar() 229 | kw63 = StringVar() 230 | kw64 = StringVar() 231 | kw65 = StringVar() 232 | kw66 = StringVar() 233 | kw67 = StringVar() 234 | kw81 = StringVar() 235 | kw82 = StringVar() 236 | kw83 = StringVar() 237 | kw84 = StringVar() 238 | kw85 = StringVar() 239 | keyWords = [kw01,kw02,kw03,kw04,kw05,kw06,kw07,kw08,kw50,kw51,kw52,kw53,kw54,kw55,kw56,kw57,kw58,kw59,kw60,kw61,kw62,kw63,kw64,kw65,kw66,kw67,kw81,kw82,kw83,kw84,kw85] 240 | 241 | root.title('CSEL Setup Tool') 242 | 243 | #Making some boxes 244 | scoreLoc = "LOCATION MISSING!" 245 | userDesktop = Entry(root,textvariable=usrDsktp) 246 | location = Label(root,text=scoreLoc) 247 | userDesktopLabel = Label(root,text="Path to Score Report and Forensics\nEx: /home/fred/Desktop/\nDon't forget the trailing '/'") 248 | userDesktopButton = Button(root,text='Save',command=updateScoreLoc) 249 | fqHead1 = Label(root,text="Create?",font=('Verdana',10,'bold')) 250 | fqHead2 = Label(root,text="Points",font=('Verdana',10,'bold')) 251 | fqHead3 = Label(root,text="Question",font=('Verdana',10,'bold')) 252 | fqHead4 = Label(root,text="Answer",font=('Verdana',10,'bold')) 253 | fqCheckbox01 = Checkbutton(root,text=fq01.name,variable=fqcb01) 254 | fqPoints01 = Entry(root,textvariable=fqpts01) 255 | fqQuest01 = Entry(root,textvariable=fquest01) 256 | fqAns01 = Entry(root,textvariable=fqans01) 257 | fqCheckbox02 = Checkbutton(root,text=fq02.name,variable=fqcb02) 258 | fqPoints02 = Entry(root,textvariable=fqpts02) 259 | fqQuest02 = Entry(root,textvariable=fquest02) 260 | fqAns02 = Entry(root,textvariable=fqans02) 261 | createForQ = Button(root,text="Create Forensics Questions",command=createForQ) 262 | checkbox01 = Checkbutton(root,text=v01.name,variable=cb01) 263 | points01 = Entry(root,textvariable=pts01) 264 | label01 = Label(root,text=v01.tip) 265 | checkbox02 = Checkbutton(root,text=v02.name,variable=cb02) 266 | points02 = Entry(root,textvariable=pts02) 267 | label02 = Label(root,text=v02.tip) 268 | checkbox03 = Checkbutton(root,text=v03.name,variable=cb03) 269 | points03 = Entry(root,textvariable=pts03) 270 | label03 = Label(root,text=v03.tip) 271 | checkbox04 = Checkbutton(root,text=v04.name,variable=cb04) 272 | points04 = Entry(root,textvariable=pts04) 273 | label04 = Label(root,text=v04.tip) 274 | checkbox05 = Checkbutton(root,text=v05.name,variable=cb05) 275 | points05 = Entry(root,textvariable=pts05) 276 | label05 = Label(root,text=v05.tip) 277 | checkbox06 = Checkbutton(root,text=v06.name,variable=cb06) 278 | points06 = Entry(root,textvariable=pts06) 279 | label06 = Label(root,text=v06.tip) 280 | checkbox07 = Checkbutton(root,text=v07.name,variable=cb07) 281 | points07 = Entry(root,textvariable=pts07) 282 | label07 = Label(root,text=v07.tip) 283 | checkbox08 = Checkbutton(root,text=v08.name,variable=cb08) 284 | points08 = Entry(root,textvariable=pts08) 285 | label08 = Label(root,text=v08.tip) 286 | #Gettting into the fancier vulnerabilities now 287 | checkbox50 = Checkbutton(root,text=v50.name,variable=cb50) 288 | points50 = Entry(root,textvariable=pts50) 289 | keywords50 = Entry(root,textvariable=kw50) 290 | label50 = Label(root,text=v50.tip) 291 | checkbox51 = Checkbutton(root,text=v51.name,variable=cb51) 292 | points51 = Entry(root,textvariable=pts51) 293 | keywords51 = Entry(root,textvariable=kw51) 294 | label51 = Label(root,text=v51.tip) 295 | checkbox52 = Checkbutton(root,text=v52.name,variable=cb52) 296 | points52 = Entry(root,textvariable=pts52) 297 | keywords52 = Entry(root,textvariable=kw52) 298 | label52 = Label(root,text=v52.tip) 299 | checkbox53 = Checkbutton(root,text=v53.name,variable=cb53) 300 | points53 = Entry(root,textvariable=pts53) 301 | keywords53 = Entry(root,textvariable=kw53) 302 | label53 = Label(root,text=v53.tip) 303 | checkbox54 = Checkbutton(root,text=v54.name,variable=cb54) 304 | points54 = Entry(root,textvariable=pts54) 305 | keywords54 = Entry(root,textvariable=kw54) 306 | label54 = Label(root,text=v54.tip) 307 | checkbox55 = Checkbutton(root,text=v55.name,variable=cb55) 308 | points55 = Entry(root,textvariable=pts55) 309 | keywords55 = Entry(root,textvariable=kw55) 310 | label55 = Label(root,text=v55.tip) 311 | checkbox56 = Checkbutton(root,text=v56.name,variable=cb56) 312 | points56 = Entry(root,textvariable=pts56) 313 | keywords56 = Entry(root,textvariable=kw56) 314 | label56 = Label(root,text=v56.tip) 315 | checkbox57 = Checkbutton(root,text=v57.name,variable=cb57) 316 | points57 = Entry(root,textvariable=pts57) 317 | keywords57 = Entry(root,textvariable=kw57) 318 | label57 = Label(root,text=v57.tip) 319 | checkbox58 = Checkbutton(root,text=v58.name,variable=cb58) 320 | points58 = Entry(root,textvariable=pts58) 321 | keywords58 = Entry(root,textvariable=kw58) 322 | label58 = Label(root,text=v58.tip) 323 | checkbox59 = Checkbutton(root,text=v59.name,variable=cb59) 324 | points59 = Entry(root,textvariable=pts59) 325 | keywords59 = Entry(root,textvariable=kw59) 326 | label59 = Label(root,text=v59.tip) 327 | checkbox60 = Checkbutton(root,text=v60.name,variable=cb60) 328 | points60 = Entry(root,textvariable=pts60) 329 | keywords60 = Entry(root,textvariable=kw60) 330 | label60 = Label(root,text=v60.tip) 331 | checkbox61 = Checkbutton(root,text=v61.name,variable=cb61) 332 | points61 = Entry(root,textvariable=pts61) 333 | keywords61 = Entry(root,textvariable=kw61) 334 | label61 = Label(root,text=v61.tip) 335 | checkbox62 = Checkbutton(root,text=v62.name,variable=cb62) 336 | points62 = Entry(root,textvariable=pts62) 337 | keywords62 = Entry(root,textvariable=kw62) 338 | label62 = Label(root,text=v62.tip) 339 | checkbox63 = Checkbutton(root,text=v63.name,variable=cb63) 340 | points63 = Entry(root,textvariable=pts63) 341 | keywords63 = Entry(root,textvariable=kw63) 342 | label63 = Label(root,text=v63.tip) 343 | checkbox64 = Checkbutton(root,text=v64.name,variable=cb64) 344 | points64 = Entry(root,textvariable=pts64) 345 | keywords64 = Entry(root,textvariable=kw64) 346 | label64 = Label(root,text=v64.tip) 347 | checkbox65 = Checkbutton(root,text=v65.name,variable=cb65) 348 | points65 = Entry(root,textvariable=pts65) 349 | keywords65 = Entry(root,textvariable=kw65) 350 | label65 = Label(root,text=v65.tip) 351 | checkbox66 = Checkbutton(root,text=v66.name,variable=cb66) 352 | points66 = Entry(root,textvariable=pts66) 353 | keywords66 = Entry(root,textvariable=kw66) 354 | label66 = Label(root,text=v66.tip) 355 | checkbox67 = Checkbutton(root,text=v67.name,variable=cb67) 356 | points67 = Entry(root,textvariable=pts67) 357 | keywords67 = Entry(root,textvariable=kw67) 358 | label67 = Label(root,text=v67.tip) 359 | checkbox81 = Checkbutton(root,text=v81.name,variable=cb81) 360 | keywords81 = Entry(root,textvariable=kw81) 361 | label81 = Label(root,text=v81.tip) 362 | checkbox82 = Checkbutton(root,text=v82.name,variable=cb82) 363 | keywords82 = Entry(root,textvariable=kw82) 364 | label82 = Label(root,text=v82.tip) 365 | checkbox83 = Checkbutton(root,text=v83.name,variable=cb83) 366 | keywords83 = Entry(root,textvariable=kw83) 367 | label83 = Label(root,text=v83.tip) 368 | checkbox84 = Checkbutton(root,text=v84.name,variable=cb84) 369 | keywords84 = Entry(root,textvariable=kw84) 370 | label84 = Label(root,text=v84.tip) 371 | checkbox85 = Checkbutton(root,text=v85.name,variable=cb85) 372 | keywords85 = Entry(root,textvariable=kw85) 373 | label85 = Label(root,text=v85.tip) 374 | 375 | submit = Button(root,text='Write to Config',command=submitCallback) 376 | 377 | #Pack it up...errr GRID it up! 378 | location.grid(row=0,column=1) 379 | userDesktop.grid(row=0,column=2) 380 | userDesktopLabel.grid(row=0,column=3,sticky=W) 381 | userDesktopButton.grid(row=0,column=4,sticky=W) 382 | fqCheckbox01.grid(row=5,column=1,sticky=W) 383 | fqPoints01.grid(row=5,column=2) 384 | fqQuest01.grid(row=5,column=3) 385 | fqAns01.grid(row=5,column=4,sticky=W) 386 | fqCheckbox02.grid(row=6,column=1,sticky=W) 387 | fqPoints02.grid(row=6,column=2) 388 | fqQuest02.grid(row=6,column=3) 389 | fqAns02.grid(row=6,column=4,sticky=W) 390 | createForQ.grid(row=7,column=4,sticky=W) 391 | 392 | #Let's make a table! 393 | head1 = Label(root,text="Score?",font=('Verdana',10,'bold')) 394 | head2 = Label(root,text="Point Value",font=('Verdana',10,'bold')) 395 | head3 = Label(root,text="Explanation",font=('Verdana',10,'bold')) 396 | head4 = Label(root,text="Score?",font=('Verdana',10,'bold')) 397 | head5 = Label(root,text="Point Value",font=('Verdana',10,'bold')) 398 | head6 = Label(root,text="Keywords/Values",font=('Verdana',10,'bold')) 399 | head7 = Label(root,text="Explanation",font=('Verdana',10,'bold')) 400 | 401 | fqHead1.grid(row=3,column=1) 402 | fqHead2.grid(row=3,column=2) 403 | fqHead3.grid(row=3,column=3) 404 | fqHead4.grid(row=3,column=4,sticky=W) 405 | head1.grid(row=10,column=1) 406 | head2.grid(row=10,column=2) 407 | head3.grid(row=10,column=3) 408 | head4.grid(row=49,column=1) 409 | head5.grid(row=49,column=2) 410 | head6.grid(row=49,column=3) 411 | head7.grid(row=49,column=4) 412 | checkbox01.grid(row=11,column=1,sticky=W) 413 | points01.grid(row=11,column=2) 414 | label01.grid(row=11,column=3,sticky=W) 415 | checkbox02.grid(row=12,column=1,sticky=W) 416 | points02.grid(row=12,column=2) 417 | label02.grid(row=12,column=3,sticky=W) 418 | checkbox03.grid(row=13,column=1,sticky=W) 419 | points03.grid(row=13,column=2) 420 | label03.grid(row=13,column=3,sticky=W) 421 | checkbox04.grid(row=14,column=1,sticky=W) 422 | points04.grid(row=14,column=2) 423 | label04.grid(row=14,column=3,sticky=W) 424 | checkbox05.grid(row=15,column=1,sticky=W) 425 | points05.grid(row=15,column=2) 426 | label05.grid(row=15,column=3,sticky=W) 427 | checkbox06.grid(row=16,column=1,sticky=W) 428 | points06.grid(row=16,column=2) 429 | label06.grid(row=16,column=3,sticky=W) 430 | checkbox07.grid(row=17,column=1,sticky=W) 431 | points07.grid(row=17,column=2) 432 | label07.grid(row=17,column=3,sticky=W) 433 | checkbox08.grid(row=1,column=1,sticky=W) 434 | #points08.grid(row=18,column=2) 435 | label08.grid(row=1,column=2,sticky=W) 436 | checkbox50.grid(row=50,column=1,sticky=W) 437 | points50.grid(row=50,column=2) 438 | keywords50.grid(row=50,column=3) 439 | label50.grid(row=50,column=4,sticky=W) 440 | checkbox51.grid(row=51,column=1,sticky=W) 441 | points51.grid(row=51,column=2) 442 | keywords51.grid(row=51,column=3) 443 | label51.grid(row=51,column=4,sticky=W) 444 | checkbox52.grid(row=52,column=1,sticky=W) 445 | points52.grid(row=52,column=2) 446 | keywords52.grid(row=52,column=3) 447 | label52.grid(row=52,column=4,sticky=W) 448 | checkbox53.grid(row=53,column=1,sticky=W) 449 | points53.grid(row=53,column=2) 450 | keywords53.grid(row=53,column=3) 451 | label53.grid(row=53,column=4,sticky=W) 452 | checkbox54.grid(row=54,column=1,sticky=W) 453 | points54.grid(row=54,column=2) 454 | keywords54.grid(row=54,column=3) 455 | label54.grid(row=54,column=4,sticky=W) 456 | checkbox55.grid(row=55,column=1,sticky=W) 457 | points55.grid(row=55,column=2) 458 | keywords55.grid(row=55,column=3) 459 | label55.grid(row=55,column=4,sticky=W) 460 | checkbox56.grid(row=56,column=1,sticky=W) 461 | points56.grid(row=56,column=2) 462 | keywords56.grid(row=56,column=3) 463 | label56.grid(row=56,column=4,sticky=W) 464 | checkbox57.grid(row=57,column=1,sticky=W) 465 | points57.grid(row=57,column=2) 466 | keywords57.grid(row=57,column=3) 467 | label57.grid(row=57,column=4,sticky=W) 468 | checkbox58.grid(row=58,column=1,sticky=W) 469 | points58.grid(row=58,column=2) 470 | keywords58.grid(row=58,column=3) 471 | label58.grid(row=58,column=4,sticky=W) 472 | checkbox59.grid(row=59,column=1,sticky=W) 473 | points59.grid(row=59,column=2) 474 | keywords59.grid(row=59,column=3) 475 | label59.grid(row=59,column=4,sticky=W) 476 | checkbox60.grid(row=60,column=1,sticky=W) 477 | points60.grid(row=60,column=2) 478 | keywords60.grid(row=60,column=3) 479 | label60.grid(row=60,column=4,sticky=W) 480 | checkbox61.grid(row=61,column=1,sticky=W) 481 | points61.grid(row=61,column=2) 482 | keywords61.grid(row=61,column=3) 483 | label61.grid(row=61,column=4,sticky=W) 484 | checkbox62.grid(row=62,column=1,sticky=W) 485 | points62.grid(row=62,column=2) 486 | keywords62.grid(row=62,column=3) 487 | label62.grid(row=62,column=4,sticky=W) 488 | checkbox63.grid(row=63,column=1,sticky=W) 489 | points63.grid(row=63,column=2) 490 | keywords63.grid(row=63,column=3) 491 | label63.grid(row=63,column=4,sticky=W) 492 | checkbox64.grid(row=64,column=1,sticky=W) 493 | points64.grid(row=64,column=2) 494 | keywords64.grid(row=64,column=3) 495 | label64.grid(row=64,column=4,sticky=W) 496 | checkbox65.grid(row=65,column=1,sticky=W) 497 | points65.grid(row=65,column=2) 498 | keywords65.grid(row=65,column=3) 499 | label65.grid(row=65,column=4,sticky=W) 500 | checkbox66.grid(row=66,column=1,sticky=W) 501 | points66.grid(row=66,column=2) 502 | keywords66.grid(row=66,column=3) 503 | label66.grid(row=66,column=4,sticky=W) 504 | checkbox67.grid(row=67,column=1,sticky=W) 505 | points67.grid(row=67,column=2) 506 | keywords67.grid(row=67,column=3) 507 | label67.grid(row=67,column=4,sticky=W) 508 | checkbox81.grid(row=81,column=1,sticky=W) 509 | keywords81.grid(row=81,column=2) 510 | label81.grid(row=81,column=3,columnspan=2,sticky=W) 511 | checkbox82.grid(row=82,column=1,sticky=W) 512 | keywords82.grid(row=82,column=2) 513 | label82.grid(row=82,column=3,columnspan=2,sticky=W) 514 | checkbox83.grid(row=83,column=1,sticky=W) 515 | keywords83.grid(row=83,column=2) 516 | label83.grid(row=83,column=3,columnspan=2,sticky=W) 517 | checkbox84.grid(row=84,column=1,sticky=W) 518 | keywords84.grid(row=84,column=2) 519 | label84.grid(row=84,column=3,columnspan=2,sticky=W) 520 | checkbox85.grid(row=85,column=1,sticky=W) 521 | keywords85.grid(row=85,column=2) 522 | label85.grid(row=85,column=3,columnspan=2,sticky=W) 523 | 524 | submit.grid(row=99,column=3) 525 | 526 | root.mainloop() -------------------------------------------------------------------------------- /csel.cfg: -------------------------------------------------------------------------------- 1 | #This config file was generated by configurator.py 2 | 3 | -------------------------------------------------------------------------------- /iguana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FWSquatch/CSEL/f498f0ecfe225774ccbc230bd9d80625f6baf7b9/iguana.png -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Merge the config with the code, output it to csel file 4 | echo 'Merging csel.cfg with payload...' 5 | cat csel.cfg payload > /usr/local/bin/csel_SCORING_ENGINE_DO_NOT_TOUCH 6 | sed -i "s/%KERNEL%/"`uname -r`"/g" /usr/local/bin/csel_SCORING_ENGINE_DO_NOT_TOUCH 7 | sed -i "s/%INSTALLDATE%/"`date +%s`"/g" /usr/local/bin/csel_SCORING_ENGINE_DO_NOT_TOUCH 8 | echo -e 'DONE\nInstalling csel into /usr/local/bin...' 9 | chmod 777 /usr/local/bin/csel_SCORING_ENGINE_DO_NOT_TOUCH #Make it executable 10 | 11 | #Check for crontab entry, add it if it doesn't exist 12 | echo -e 'DONE\nAdding crontab entry...' 13 | if [[ $(crontab -l -u root | grep csel) ]] ; then :; else 14 | (crontab -l -u root ; echo "* * * * * /bin/bash /usr/local/bin/csel_SCORING_ENGINE_DO_NOT_TOUCH")| crontab - 15 | fi 16 | 17 | #Check for CYBER folder, create if it doesn't exist 18 | echo -e 'DONE\nCreating /etc/CYBERPATRIOT directory for icons...' 19 | if [ ! -d "/etc/CYBERPATRIOT_DO_NOT_REMOVE" ] 20 | then 21 | mkdir /etc/CYBERPATRIOT_DO_NOT_REMOVE 22 | cp logo.png /etc/CYBERPATRIOT_DO_NOT_REMOVE/logo.png 23 | cp iguana.png /etc/CYBERPATRIOT_DO_NOT_REMOVE/iguana.png 24 | fi 25 | 26 | #Fire csel to create the initial Score Report 27 | echo -e 'DONE\nFiring csel for the first time...' 28 | csel_SCORING_ENGINE_DO_NOT_TOUCH 29 | 30 | #Finish up 31 | scoreReportLoc=$( grep -Po '(?<=index=\().*?(?=\))' csel.cfg ) 32 | echo -e 'DONE\n----------------------------------\n\nScore Report is located at:' $scoreReportLoc 33 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/FWSquatch/CSEL/f498f0ecfe225774ccbc230bd9d80625f6baf7b9/logo.png -------------------------------------------------------------------------------- /payload: -------------------------------------------------------------------------------- 1 | #DO NOT MESS WITH THIS FILE# 2 | 3 | addPosPoints(){ #Use: posPoints 4 | posPoints=$[$posPoints + $1] 5 | } 6 | 7 | addScore(){ #Add points to your total score 8 | imageScore=$[$imageScore + $1] 9 | } 10 | 11 | avUpdated(){ #Check to see that clamav has been updated 12 | if [ -z "$avUpdated" ]; then :; else addPosPoints ${#avUpdated[@]}*$avUpdatedValue 13 | if [ -e /var/log/clamav/freshclam.log ] ; then 14 | avUpdateDate=$(date -d $(grep 'main.cvd is up' /var/log/clamav/freshclam.log | awk '{print $2"-"$3"-"$5}' | tail -1) +%s) 15 | installDate=$(($installDate - 86400)) 16 | if (( "$avUpdateDate" >= "$installDate" )) ; then 17 | recordHit 'AV has been updated. ' $avUpdatedValue 18 | else 19 | recordMiss 'AV ' 20 | fi 21 | else 22 | recordMiss 'AV ' 23 | fi 24 | fi 25 | } 26 | 27 | badCron(){ #Check that bad cronjobs are deleted or commented out. 28 | if [ -z "$badCron" ]; then :; else addPosPoints $badCronValue 29 | if [ -z /var/spool/cron/crontabs/${badCron[0]} ]; then #If user crontab has been deleted 30 | recordHit 'Cron job in '${badCron[0]}' disabled.' $badCronValue 31 | else 32 | if [[ $(crontab -u ${badCron[0]} -l | grep ^# | grep ${badCron[1]}) ]]; then #If bad line has been commented out 33 | recordHit 'Cron job in '${badCron[0]}' disabled.' $badCronValue 34 | else 35 | if [[ $(crontab -u ${badCron[0]} -l | grep ${badCron[1]}) ]]; then 36 | recordMiss ' Crontab ' 37 | else 38 | recordHit 'Cron job in '${badCron[0]}' disabled.' $badCronValue #If bad line has been deleted 39 | fi 40 | fi 41 | fi 42 | fi 43 | } 44 | 45 | badFile(){ #Check for bad files 46 | if [ -z "$badFile" ]; then :; else addPosPoints ${#badFile[@]}*$badFileValue 47 | for i in "${badFile[@]}" ; do 48 | if [ -e "$i" ] ; then 49 | recordMiss 'File management ' 50 | else 51 | recordHit 'File '$i' deleted.' $badFileValue 52 | fi 53 | done 54 | fi 55 | } 56 | 57 | badProgram(){ #Check for bad programs 58 | if [ -z "$badProgram" ]; then :; else addPosPoints ${#badProgram[@]}*$badProgramValue 59 | for i in "${badProgram[@]}" ; do 60 | if apt-cache policy $i | grep "Installed: (none)" > /dev/null ; then 61 | recordHit 'Program '$i' uninstalled.' $badProgramValue 62 | else 63 | recordMiss 'Bad program management ' 64 | fi 65 | done 66 | fi 67 | } 68 | 69 | badUser(){ #Check for bad users 70 | if [ -z "$badUser" ]; then :; else addPosPoints ${#badUser[@]}*$badUserValue 71 | for i in "${badUser[@]}" ; do 72 | if getent passwd $i > /dev/null 2>&1; then 73 | recordMiss "User management " 74 | else 75 | recordHit 'User '$i' has been deleted.' $badUserValue 76 | fi 77 | done 78 | fi 79 | } 80 | 81 | backdoor(){ #Look for process running with the name $backdoor 82 | if [ -z "$backdoor" ]; then :; else addPosPoints ${#backdoor[@]}*$backdoorValue 83 | for i in "${backdoor[@]}" ; do 84 | if pgrep -x $i > /dev/null ; then 85 | recordMiss 'Backdoor ' 86 | else 87 | recordHit 'Backdoor '$i' removed.' $backdoorValue 88 | fi 89 | done 90 | fi 91 | } 92 | 93 | changePassword(){ #Check certain users for blank passwords 94 | if [ -z "$changePassword" ]; then :; else addPosPoints ${#changePassword[@]}*$changePasswordValue 95 | for i in "${changePassword[@]}" ; do #Check for blank passwords 96 | if [[ $(getent shadow | grep $i\:\:) ]] ; then 97 | recordMiss Password 98 | else 99 | recordHit 'User '$i' password has been changed.' $changePasswordValue 100 | fi 101 | done 102 | fi 103 | } 104 | 105 | checkFirewall(){ #Is ufw installed and enabled? 106 | if [ -z "$checkFirewall" ]; then :; else addPosPoints $checkFirewallValue 107 | if sudo ufw status | grep "Status: active" > /dev/null ; then 108 | recordHit 'Firewall enabled.' $checkFirewallValue 109 | else 110 | recordMiss 'Firewall ' 111 | fi 112 | fi 113 | } 114 | 115 | checkForensicsQuestion1(){ #Check for the correct answer in the forensics question 116 | if [ -z "$forensicsAnswer1" ]; then :; else addPosPoints ${#forensicsAnswer1[@]}*$checkForensicsQuestion1Value 117 | if grep -q "ANSWER: $forensicsAnswer1" $forensicsPath1 ; then 118 | recordHit 'Forensics Question 1 correct.' $checkForensicsQuestion1Value 119 | else 120 | recordMiss 'Forensics Question ' 121 | fi 122 | fi 123 | } 124 | 125 | checkForensicsQuestion2(){ #Check for the correct answer in the forensics question 126 | if [ -z "$forensicsAnswer2" ]; then :; else addPosPoints ${#forensicsAnswer2[@]}*$checkForensicsQuestion2Value 127 | if grep -q "ANSWER: $forensicsAnswer2" $forensicsPath2 ; then 128 | recordHit 'Forensics Question 2 correct.' $checkForensicsQuestion2Value 129 | else 130 | recordMiss 'Forensics Question ' 131 | fi 132 | fi 133 | } 134 | 135 | checkKernel(){ 136 | if [ -z "$checkKernel" ]; then :; else addPosPoints $checkKernelValue 137 | currentKernel=$(uname -r | awk -F. '{printf($1 "%02d\n", $2) }') 138 | initialKernelFormatted=$(echo $initialKernel | awk -F. '{printf($1 "%02d\n", $2) }') 139 | if (( "$currentKernel" > "$initialKernelFormatted" )) ; then 140 | recordHit 'Kernel Updated' $checkKernelValue 141 | else 142 | recordMiss 'Kernel' 143 | fi 144 | fi 145 | } 146 | 147 | checkForRoot(){ #Gotta be root 148 | if [ "$EUID" -ne 0 ] ; then 149 | echo "csel must be run as root" 150 | exit 151 | fi 152 | } 153 | 154 | checkHosts(){ #Check for certain words in the hosts file 155 | if [ -z "$checkHosts" ]; then :; else addPosPoints ${#checkHosts[@]}*$checkHostsValue 156 | for i in "${checkHosts[@]}" ; do 157 | if [[ `grep $checkHosts /etc/hosts` ]] ; then 158 | recordMiss 'Hosts file ' 159 | else 160 | recordHit $i' removed from hosts file.' $checkHostsValue 161 | fi 162 | done 163 | fi 164 | } 165 | 166 | #checkPassHist(){ #Check /etc/pam.d/common-password for password history 167 | #if [ -z "$checkPassHist" ]; then :; else addPosPoints $checkPassHistValue 168 | # if [[ `grep remember /etc/pam.d/common-password` ]] ; then #does remember exist in the file? 169 | # if [ `grep -o -P '(?<=remember=).*(?=\ )' /etc/pam.d/common-password` ] ; then #Check for value somewhere in the middle of the line 170 | # currentPassHist=$(grep -oP '(?<=remember=).*(?=\ )' /etc/pam.d/common-password ) 171 | # else #If it's not in the middle, it must be at the end of the line 172 | # currentPassHist=$(grep -oPz '(?<=remember=)(.*\n)' /etc/pam.d/common-password ) 173 | # fit 174 | # if (( "$currentPassHist" >= "$checkPassHist" )) ; then #Compare the current setting with the desired setting 175 | # recordHit "Password History is at least "$checkPassHist"." $checkPassHistValue 176 | # else 177 | # recordMiss "Password Policy" 178 | # fi 179 | # else #NO it does not exist 180 | # recordMiss "Password Policy" 181 | # fi 182 | #fi 183 | #} 184 | 185 | checkPassLength(){ #Check /etc/pam.d/common-password for min length 186 | if [ -z "$checkPassLength" ]; then :; else addPosPoints $checkPassLengthValue 187 | if [[ `grep minlen /etc/pam.d/common-password` ]] ; then #does remember exist in the file? 188 | if [ `grep -o -P '(?<=minlen=).*(?=\ )' /etc/pam.d/common-password` ] ; then #Check for value somewhere in the middle of the line 189 | currentPassLength=$(grep -oP '(?<=minlen=).*(?=\ )' /etc/pam.d/common-password ) 190 | else #If it's not in the middle, it must be at the end of the line 191 | currentPassLength=$(grep -oPz '(?<=minlen=)(.*\n)' /etc/pam.d/common-password ) 192 | fi 193 | if (( "$currentPassLength" >= "$checkPassLength" )) ; then #Compare the current setting with the desired setting 194 | recordHit "Password Length is at least "$checkPassLength"." $checkPassLengthValue 195 | else 196 | recordMiss "Password Policy" 197 | fi 198 | else #NO it does not exist 199 | recordMiss "Password Policy" 200 | fi 201 | fi 202 | } 203 | 204 | checkRelease(){ #Check for version of Ubuntu (not implemented yet) 205 | if lsb_release -a | grep trusty > /dev/null 206 | then 207 | release="trusty" 208 | else 209 | release="xenial" 210 | fi 211 | } 212 | 213 | checkStartup() { #Check /etc/rc.local for certain words 214 | if [ -z "$checkStartup" ]; then :; else addPosPoints ${#checkStartup[@]}*$checkStartupValue 215 | for i in "${checkStartup[@]}" ; do 216 | if [[ `grep $i /etc/rc.local` ]] ; then 217 | recordMiss 'Startup ' 218 | else 219 | recordHit $i' removed from /etc/rc.local file.' $checkStartupValue 220 | fi 221 | done 222 | fi 223 | } 224 | 225 | disableAutoLogin(){ #Check /etc/lightdm/lightdm.conf for an auto login account? 226 | if [ -z "$disableAutoLogin" ];then :; else addPosPoints $disableAutoLoginValue 227 | if [[ $(cat /etc/lightdm/lightdm.conf | grep ^autologin-user) ]] ; then 228 | recordMiss 'Auto login' 229 | else 230 | recordHit 'Autologin disabled.' $disableAutoLoginValue 231 | fi 232 | fi 233 | } 234 | 235 | disableGuest(){ #Check /etc/lightdm/lightdm.conf is the Guest account disabled? 236 | if [ -z "$disableGuest" ]; then :; else addPosPoints $disableGuestValue 237 | if [[ $(cat /etc/lightdm/lightdm.conf | grep allow-guest=false) ]] ; then 238 | recordHit 'Guest account disabled.' $disableGuestValue 239 | else 240 | recordMiss 'Guest account' 241 | fi 242 | fi 243 | } 244 | 245 | drawHead(){ #Create the Score Report html 246 | echo 'CSEL Score Report' > $index 247 | echo '

Cyberpatriot Scoring Engine:Linux v0.5


Your Score: #TotalScore# out of #PossiblePoints#


' >> $index 248 | } 249 | 250 | drawTail(){ #Finish up report (insert score and possible points) 251 | sed -i "s/#TotalScore#/"$imageScore"/g" $index 252 | sed -i "s/#PossiblePoints#/"$posPoints"/g" $index 253 | echo '

Developed by Josh Davis
Eastern Oklahoma County Technology Center
Feedback welcome: jdavis@eoctech.edu
' >> $index 254 | } 255 | 256 | fileContainsText1(){ 257 | if [ -z "$fileContainsText1" ]; then :; else addPosPoints ${fileContainsText1[2]} 258 | if [ -e ${fileContainsText1[0]} ]; then 259 | if grep -q "${fileContainsText1[1]}" ${fileContainsText1[0]} ; then 260 | echo ${fileContainsText1[0]} ${fileContainsText1[1]} ${fileContainsText1[2]} ${fileContainsText1[3]} 261 | if grep ^[^#] ${fileContainsText1[0]} | grep "${fileContainsText1[1]}" ; then 262 | recordHit "${fileContainsText1[3]}" ${fileContainsText1[2]} 263 | else 264 | recordMiss 'File Configuration ' 265 | fi 266 | else 267 | recordMiss 'File Configuration ' 268 | fi 269 | else 270 | recordMiss 'File Configuration ' 271 | fi 272 | fi 273 | } 274 | 275 | fileContainsText2(){ 276 | if [ -z "$fileContainsText2" ]; then :; else addPosPoints ${fileContainsText2[2]} 277 | if [ -e ${fileContainsText2[0]} ]; then 278 | if grep -q "${fileContainsText2[1]}" ${fileContainsText2[0]} ; then 279 | if grep ^[^#] ${fileContainsText2[0]} | grep "${fileContainsText2[1]}" ; then 280 | recordHit "${fileContainsText2[3]}" ${fileContainsText2[2]} 281 | else 282 | recordMiss 'File Configuration ' 283 | fi 284 | else 285 | recordMiss 'File Configuration ' 286 | fi 287 | else 288 | recordMiss 'File Configuration ' 289 | fi 290 | fi 291 | } 292 | 293 | fileNoLongerContains1(){ 294 | if [ -z "$fileNoLongerContains1" ]; then :; else addPosPoints ${fileNoLongerContains1[2]} 295 | if [ -e ${fileNoLongerContains1[0]} ]; then 296 | if grep -q "${fileNoLongerContains1[1]}" ${fileNoLongerContains1[0]} ; then 297 | if grep -q ^[^#] ${fileNoLongerContains1[0]} | grep "${fileNoLongerContains1[1]}" ; then 298 | recordMiss 'File Configuration ' 299 | else 300 | recordHit "${fileNoLongerContains1[3]}" ${fileNoLongerContains1[2]} 301 | fi 302 | else 303 | recordHit "${fileNoLongerContains1[3]}" ${fileNoLongerContains1[2]} 304 | fi 305 | else 306 | recordHit "${fileNoLongerContains1[3]}" ${fileNoLongerContains1[2]} 307 | fi 308 | fi 309 | } 310 | 311 | fileNoLongerContains2(){ 312 | if [ -z "$fileNoLongerContains2" ]; then :; else addPosPoints ${fileNoLongerContains2[2]} 313 | if [ -e ${fileNoLongerContains2[0]} ]; then 314 | if grep -q "${fileNoLongerContains2[1]}" ${fileNoLongerContains2[0]} ; then 315 | if grep -q ^[^#] ${fileNoLongerContains2[0]} | grep "${fileNoLongerContains2[1]}" ; then 316 | recordMiss 'File Configuration ' 317 | else 318 | recordHit "${fileNoLongerContains2[3]}" ${fileNoLongerContains2[2]} 319 | fi 320 | else 321 | recordHit "${fileNoLongerContains2[3]}" ${fileNoLongerContains2[2]} 322 | fi 323 | else 324 | recordHit "${fileNoLongerContains2[3]}" ${fileNoLongerContains2[2]} 325 | fi 326 | fi 327 | } 328 | 329 | goodProgram(){ #Check for good programs 330 | if [ -z "$goodProgram" ]; then :; else addPosPoints ${#goodProgram[@]}*$goodProgramValue 331 | for i in "${goodProgram[@]}" ; do 332 | if apt-cache policy $i | grep "Installed: (none)" > /dev/null ; then 333 | recordMiss 'Good program management ' 334 | else 335 | recordHit 'Program '$i' installed.' $goodProgramValue 336 | fi 337 | done 338 | fi 339 | } 340 | 341 | goodUser(){ #Penalize for deleting good users 342 | if [ -z "$goodUser" ]; then :; else 343 | for i in "${goodUser[@]}" ; do 344 | if getent passwd $i > /dev/null 2>&1; then :; else #If goodUser exists, do nothing, else penalize 345 | recordPenalty "User "$i" deleted" $goodUserValue 346 | fi 347 | done 348 | fi 349 | } 350 | 351 | disableUserGreeter(){ 352 | if [ -z "$disableUserGreeter" ]; then :; else addPosPoints $disableUserGreeterValue 353 | if [[ $(cat /etc/lightdm/lightdm.conf | grep greeter-hide-users=true) ]] ; then 354 | recordHit 'Show usernames on login greeter is disabled.' $disableUserGreeterValue 355 | else 356 | recordMiss 'Greeter' 357 | fi 358 | fi 359 | } 360 | 361 | maxLoginTries(){ #Check max login threshold 362 | if [ -z "$maxLoginTries" ]; then :; else addPosPoints $maxLoginTriesValue 363 | currentMax=$(cat /etc/login.defs | grep ^LOGIN_RETRIES | awk '{print $2;}') #Look at login.defs 364 | if (( "$currentMax" <= "$maxLoginTries" )) ; then 365 | recordHit 'Max Login Tries is at most '$maxLoginTries'.' $maxLoginTriesValue 366 | else 367 | recordMiss 'Password Policy' 368 | fi 369 | fi 370 | } 371 | 372 | maxPassAge(){ #Check max password age 373 | if [ -z "$maxPassAge" ]; then :; else addPosPoints $maxPassAgeValue 374 | currentMax=$(cat /etc/login.defs | grep ^PASS_MAX_DAYS | awk '{print $2;}') #Look in login.defs 375 | if (( "$currentMax" <= "$maxPassAge" )) ; then 376 | recordHit 'Max Password age is at most '$maxPassAge'.' $maxPassAgeValue 377 | else 378 | recordMiss 'Password Age' 379 | fi 380 | fi 381 | } 382 | 383 | minPassAge(){ #Check minimum password age 384 | if [ -z "$minPassAge" ]; then :; else addPosPoints $minPassAgeValue 385 | currentMin=$(cat /etc/login.defs | grep ^PASS_MIN_DAYS | awk '{print $2;}') #find current minimum 386 | if (( "$currentMin" < "$minPassAge" )) ; then 387 | recordMiss 'Password Policy' 388 | else 389 | recordHit 'Minimum Password age is at least '$minPassAge'.' $minPassAgeValue 390 | fi 391 | fi 392 | } 393 | 394 | newUser(){ 395 | if [ -z "$newUser" ]; then :; else addPosPoints $newUserValue 396 | for i in "${newUser[@]}" ; do 397 | if getent passwd $i > /dev/null 2>&1; then 398 | recordHit 'User '$i' has been created.' $newUserValue 399 | else 400 | recordMiss "User management " 401 | fi 402 | done 403 | fi 404 | } 405 | 406 | recordHit(){ #Use: recordHit 407 | echo '

' $1 '('$2' points)

' >> $index 408 | addScore $2 409 | } 410 | 411 | recordMiss(){ #Use: recordMiss 412 | if [ "$silentMiss" == "y" ]; then :; else 413 | echo '

MISS '$1' Issue

' >> $index 414 | fi 415 | } 416 | 417 | recordPenalty(){ #Use: recordPenalty 418 | echo '

'$1' ('$2' points)

' >> $index 419 | addScore $2 420 | } 421 | 422 | removeAdmin(){ #Check certain uses to see if they have been removed from admin 423 | if [ -z "$removeAdmin" ]; then :; else addPosPoints ${#removeAdmin[@]}*$removeAdminValue 424 | for i in "${removeAdmin[@]}" ; do 425 | if [[ $(getent group sudo | grep $i) ]] ; then #If the user exists in admin group 426 | recordMiss Admin 427 | else 428 | recordHit $i' removed from Admin group.' $removeAdminValue 429 | fi 430 | done 431 | fi 432 | } 433 | 434 | secureSudoers(){ #Check /etc/suders for specific text 435 | if [ -z "$secureSudoers" ]; then :; else addPosPoints ${#secureSudoers[@]}*$secureSudoersValue 436 | for i in "${secureSudoers[@]}" ; do 437 | if [[ $(sudo cat /etc/sudoers | grep $i) ]] ; then #If specific text exists in sudoers file 438 | recordMiss 'Sudoers' 439 | else 440 | recordHit '/etc/sudoers file secured.' $secureSudoersValue 441 | fi 442 | done 443 | fi 444 | } 445 | 446 | updatePackListsInt() { #Update package lists interval (should normally be set to 1) 447 | if [ -z "$updatePackListsInt" ]; then :; else addPosPoints ${#updatePackListsInt[@]}*$updatePackListsIntValue 448 | for i in "${updatePackListsInt[@]}" ; do 449 | if [[ `grep -oP '(?<=Update-Package-Lists ").' /etc/apt/apt.conf.d/10periodic` -eq $i ]] ; then 450 | recordHit 'Updates set to check every '$i' day(s).' $updatePackListsIntValue 451 | else 452 | recordMiss 'Updates' 453 | fi 454 | done 455 | fi 456 | } 457 | 458 | updateAutoInstall(){ 459 | if [ -z "$updateAutoInstall" ]; then :; else addPosPoints ${#updateAutoInstall[@]}*$updateAutoInstallValue 460 | if [[ `grep -oP '(?<=Unattended-Upgrade ").' /etc/apt/apt.conf.d/10periodic` -eq $updateAutoInstall ]] ; then 461 | recordHit 'Updates set to auto-install.' $updateAutoInstallValue 462 | else 463 | recordMiss 'Updates' 464 | fi 465 | fi 466 | } 467 | 468 | groupExists(){ 469 | if [ -z "$groupExists" ]; then :; else addPosPoints ${groupExists[1]} 470 | if grep -q ${groupExists[0]} /etc/group; then 471 | recordHit ${groupExists[0]}' has been created.' ${groupExists[1]} 472 | else 473 | recordMiss 'Group' 474 | fi 475 | fi 476 | } 477 | 478 | userInGroup(){ 479 | if [ -z "$userInGroup" ]; then :; else addPosPoints ${userInGroup[2]} 480 | if grep ${userInGroup[0]} /etc/group | grep -q ${userInGroup[1]}; then 481 | recordHit ${userInGroup[0]}' is in '${userInGroup[1]}'.' ${userInGroup[2]} 482 | else 483 | recordMiss 'User in Group' 484 | fi 485 | fi 486 | } 487 | #---------------------Categories---------------------# 488 | 489 | userManagement(){ 490 | echo '

USER MANAGEMENT

' >> $index 491 | goodUser 492 | badUser 493 | newUser 494 | changePassword 495 | removeAdmin 496 | secureSudoers 497 | groupExists 498 | userInGroup 499 | } 500 | 501 | securityPolicies(){ 502 | echo '

SECURITY POLICIES

' >> $index 503 | disableGuest 504 | disableAutoLogin 505 | disableUserGreeter 506 | minPassAge 507 | maxPassAge 508 | maxLoginTries 509 | #checkPassHist 510 | checkPassLength 511 | #checkLockoutDur Not implemented yet 512 | } 513 | 514 | programManagement(){ 515 | echo '

PROGRAMS

' >> $index 516 | goodProgram 517 | badProgram 518 | } 519 | 520 | fileManagement(){ 521 | echo '

FILE MANAGEMENT

' >> $index 522 | badFile 523 | } 524 | 525 | miscPoints(){ 526 | echo '

MISCELLANEOUS

' >> $index 527 | backdoor 528 | checkHosts 529 | badCron 530 | checkFirewall 531 | checkStartup 532 | checkForensicsQuestion1 533 | checkForensicsQuestion2 534 | updatePackListsInt 535 | updateAutoInstall 536 | avUpdated 537 | checkKernel 538 | fileContainsText1 539 | fileContainsText2 540 | fileNoLongerContains1 541 | fileNoLongerContains2 542 | } 543 | 544 | #---------------------Main Loop---------------------# 545 | 546 | checkForRoot 547 | checkRelease 548 | drawHead 549 | userManagement 550 | securityPolicies 551 | programManagement 552 | fileManagement 553 | miscPoints 554 | drawTail 555 | --------------------------------------------------------------------------------