Another technique frequently used is to download an encrypted payload and decrypt it at runtime. There are various of ways of encrypting a payload. Some examples below:
Although these are probably better at encrypting our payload I found XOR encryption to be sufficient most times. Let's write a quick encryption code that takes our shellcode file as an argument and writes a copy of the encrypted file.
Encryption
main.go
packagemainimport("fmt""log""os")funcmain(){key:=byte(0x9A)iflen(os.Args)<2{fmt.Println("Usage: encrypt <path>")os.Exit(1)}// Get the path from the command line argumentpath:=os.Args[1]_,err:=os.Stat(path)iferr!=nil{log.Fatalf("[FATAL] File %s doesn't exist",path)}fmt.Println("[+] Reading bytes of shellcode")// Read the entire file into a byte slicefileData,err:=os.ReadFile(path)iferr!=nil{log.Fatalf("[FATAL] Error reading file:",err)}// Encrypt data and add to encryptedData encryptedData:=make([]byte,len(fileData))fmt.Println("[+] Encrypting bytes of shellcode")fori:=0;i<len(encryptedData);i++{encryptedData[i]=fileData[i]^key}fmt.Printf("[+] Writing encoded bytes at %s",path+"_ENC")// Write encryptedData to fileos.WriteFile(path+"_ENC",encryptedData,0644)}
Lines 10 - 23: Check if the argument was passed to our program and if the file actually exists. If not the program terminates.
Lines 24-30: Reads the contents of the file in the 'fileData' byte slice
Lines 31-36: Creates a new byte slice called encryptedData, then loops through the contents of fileData and XORs them with the key provided on line 10 and adds the data in encryptedData.
Lines 37-39: Writes the contents of the encrytedData and outputs the file at the same directory with "_ENC" appended at the end of the filename
Decrypt
The same code can be reused in our shellcode injection code to decrypt the payload.