Przeglądaj źródła

initial polling mode

Marius Schwarz 4 lat temu
rodzic
commit
ef31c4f009
6 zmienionych plików z 174 dodań i 64 usunięć
  1. 9 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 1 1
      src/dns.rs
  4. 5 0
      src/main.rs
  5. 138 63
      src/server.rs
  6. 20 0
      src/utilities.rs

+ 9 - 0
Cargo.lock

@@ -1,5 +1,14 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
+[[package]]
+name = "base64"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
+
 [[package]]
 name = "dns-client"
 version = "0.1.0"
+dependencies = [
+ "base64",
+]

+ 1 - 0
Cargo.toml

@@ -7,3 +7,4 @@ edition = "2018"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
+base64 = "0.13.0"

+ 1 - 1
src/dns.rs

@@ -720,7 +720,7 @@ impl BytePacketBuffer {
                     break
                 }
                 outstr.push_str(delim);
-                let domain = &String::from_utf8_lossy(self.get_range(lpos, len).unwrap()).to_lowercase();
+                let domain = &String::from_utf8_lossy(self.get_range(lpos, len).unwrap()).to_string();
                 outstr.push_str(domain);
                 delim = ".";
                 // move forward the local pos

+ 5 - 0
src/main.rs

@@ -1,5 +1,6 @@
 mod dns;
 mod server;
+mod utilities;
 
 use dns::*;
 use server::*;
@@ -40,6 +41,7 @@ fn main() {
         if args.contains(&"--chat".to_string()) {
             let tunnel = DnsTunnel::new("swrzm.de".to_string(), "127.0.0.1".to_string(), port);
             tunnel.connect();
+
             loop {
                 print!(">> ");
                 let mut inp = String::new();
@@ -47,6 +49,7 @@ fn main() {
                 stdin().read_line(&mut inp).expect("Did not enter a correct string");
                 inp.pop();
                 tunnel.send_string(inp);
+                tunnel.poll();
             }
         } else {
             println!("[-] --data needed");
@@ -54,6 +57,7 @@ fn main() {
     }
 
 
+    /*
     let qname = "_acme-challenge.swrzm.de";
     let qname = "google.de";
     let qtype = QueryType::A;
@@ -74,4 +78,5 @@ fn main() {
         println!("{:#?}", a);
     }
 
+    */
 }

+ 138 - 63
src/server.rs

@@ -1,6 +1,8 @@
 use std::net::UdpSocket;
 use crate::dns::*;
 use std::str;
+use crate::utilities::*;
+
 
 pub struct DnsServer {
 }
@@ -167,6 +169,9 @@ impl DnsTunnel {
         let socket = UdpSocket::bind(("0.0.0.0", port)).unwrap();
 
         // starting main loop
+        let mut poll_status = PollStatus::NONE;
+
+
         loop {
             let mut response_buffer = BytePacketBuffer::new();
 
@@ -180,34 +185,107 @@ impl DnsTunnel {
                 if quest.qtype == QueryType::TXT {
 
                     let data = &quest.name;
+                    let mut data: Vec<&str> = data.split(".").collect();
+                    let data = data[0];
 
-                    if !data.contains("init") &&
-                        !data.contains("start") &&
-                        !data.contains("end") {
+                    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") {
+                    } else if data.contains("END") {
                         println!("[*] Message: {}", full_data);
                         full_data = String::new();
+                    } else if data.contains("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();
+                                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;
+                            },
+                            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();
+                                poll_status = PollStatus::NONE;
+                            }
+                        }
+
+
                     }
-                    //if data.contains("tun") {
-                        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();
-                    //}
+                    // 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);
                 }
             }
         }
     }
 
+    /// this is not only checking for an `ACK` as answer, but gets the returned
+    /// data
+    fn send_recv(&self, message: &str) -> Result<String, ()> {
+
+        // Take care of the encoding
+        let bytes = xor(message.as_bytes(), 0xF5);
+        let message = &b64encode(bytes);
+
+        // Craft new request with `INIT`
+        let mut pkt = self.get_txt_request(&self.domain, message.to_string());
+        let resp = pkt.send((&self.server, self.port));
+
+        // Check the answers
+        if resp.answers.len() < 1 {
+            return Err(());
+        }
+
+        let record = match &resp.answers[0] {
+            DnsRecord::TXT {
+                ref domain,
+                len,
+                ref txt,
+                ttl
+            } => {
+                return Ok(txt.to_string())
+            }
+            _ => {
+                    return Err(());
+            }
+        };
+        return Err(());
+
+    }
     /// Check if the remote server answers a simple `TUN` message with the
     /// answer `ACK`, this means that the server is available and can
     /// send back data.
     fn send_chunk(&self, message: &str) -> bool {
 
+
+        // Take care of the encoding
+        let bytes = xor(message.as_bytes(), 0xF5);
+        let message = &b64encode(bytes);
+
         // Craft new request with `INIT`
         let mut pkt = self.get_txt_request(&self.domain, message.to_string());
         let resp = pkt.send((&self.server, self.port));
@@ -248,67 +326,34 @@ impl DnsTunnel {
         self.send_chunk("END")
     }
 
-    /// Sends the data suplied in `data` via DNS tunneling to the server
-    /*
-    pub fn tunnel_client(port: u16, data: &String) {
-
-        let mut established = false;
-
-        println!("Sending {}", data);
-        let mut pkt = DnsTunnel::get_txt_request("swrzm.de", "TUN".to_string());
-
-        let server = ("127.0.0.1", 1053);
-        let resp = pkt.send(server);
-        if resp.answers.len() >= 1 {
-            let data = &resp.answers[0];
-
-            let data = match data {
-            DnsRecord::TXT {
-                ref domain,
-                len,
-                ref txt,
-                ttl
-            } => txt,
-                _ => ""
-            };
-            if data == "ACK" {
-                established = true;
-                println!("Received ACK, tunnel established");
-            }
-        }
-
+    pub fn poll(&self) -> Result<String, ()> {
 
-        if established {
+        let mut wait_for_data = false;
+        let mut return_data = String::new();
 
-            if data.len() > 63 {
-                let chunks = data.as_bytes()
-                    .chunks(63)
-                    .map(str::from_utf8)
-                    .collect::<Result<Vec<&str>, _>>()
-                    .unwrap();
-                for split in chunks {
-                    // Send the actual DATA after the tunnel is established
-                    println!("Sending Chunk: {}", split);
+        loop {
+            if let Ok(data) = self.send_recv("POLL") {
+                match &data[..] {
+                    "START" => {
+                        println!("Start");
+                        wait_for_data = true;
+                    },
+                    "END" => {
+                        println!("END");
+                        wait_for_data = false;
+                        return Ok(return_data);
+                    },
+                    _ => {
+                        return_data.push_str(&data);
+                    }
 
-                    let mut pkt = DnsTunnel::get_txt_request("swrzm.de", split.to_string());
-                    pkt.send(server);
                 }
-            } else {
-                // Send the actual DATA after the tunnel is established
-                let mut pkt = DnsTunnel::get_txt_request("swrzm.de", data.to_string());
-                pkt.send(server);
             }
-
-
-            // Send END Packet
-            let mut pkt = DnsTunnel::get_txt_request("swrzm.de", "END".to_string());
-            let resp = pkt.send(server);
-
         }
-
+        Err(())
     }
-    */
-    fn get_txt_response(ref_pkt: DnsPacket, data: String) -> DnsPacket {
+
+    fn get_txt_response(ref_pkt: &DnsPacket, data: String) -> DnsPacket {
         let mut packet = DnsPacket::empty();
         packet.header.id = ref_pkt.header.id;
         packet.header.recursion_desired = ref_pkt.header.recursion_desired;
@@ -342,4 +387,34 @@ impl DnsTunnel {
         return res_buffer;
     }
 
+    /*
+    fn split_data(data: String) -> Vec<String> {
+        if data.len() > 63 {
+            // split the data in chunks of 63 bytes
+            let chunks = data.as_bytes()
+                .chunks(63)
+                .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);
+        }
+
+    }
+    */
+}
+
+
+enum PollStatus {
+    NONE,
+    STARTED,
+    FINISHED,
 }

+ 20 - 0
src/utilities.rs

@@ -0,0 +1,20 @@
+use base64;
+
+// bas
+pub fn b64encode(data: Vec<u8>) -> String {
+    base64::encode_config(&data, base64::URL_SAFE)
+}
+
+pub fn b64decode(data: &str) -> Vec<u8> {
+    base64::decode_config(&data, base64::URL_SAFE).unwrap()
+}
+
+pub fn xor(data: &[u8], key: u8) -> Vec<u8> {
+    let mut encoded: Vec<u8> = Vec::new();
+    for byte in data {
+        encoded.push((key ^ byte) & 0xFF);
+    }
+    return encoded;
+}
+
+