Skip to content

Conversation

@BrendanGlancy
Copy link
Contributor

So I am new to Rust programming and a junior-level developer, at best, in any language.

#22 This is an attempt to add this feature to Rust Scan, but there are definitely some problems.

From what I have gathered, nmap does a couple of things for a UDP scan; they try different packet types as well as different wait times in waiting for a response from a UDP port. This makes things very slow, as I am sure you have noticed -sU scans take forever

What I am looking for in submitting this pull request is not for it to be merged, but for suggestions from people much smarter than me so I can improve the functionality of this.

Also for the automatic nmap scan that runs after every rustscan, I imagine it would be good to change it from call_format = "nmap -vvv -p {{port}} {{ip}}" to call_format = "sudo nmap -vvv -p {{port}} {{ip}} -sU" but I couldn't figure out how to do this based on the state of my sudp flag

@bee-san
Copy link
Owner

bee-san commented May 25, 2024

Hey @BrendanGlancy , what references did you use to construct the UDP packet? As you can probably predict I will need to read the docs to review this properly

I am thinking actually take a look at it, merge it, but we don't follow Nmap's way. This will make UDP unreliable, but we'll have it.

Then we can solict people to improve upon it by creating issues for specific problems we experience.

I find it's better to merge incomplete features and improve upon them rather than wait an infinite amount of time to have the most perfect feature :)

@BrendanGlancy
Copy link
Contributor Author

BrendanGlancy commented May 26, 2024

@bee-san Thanks for looking at this! If you're talking about udp_packets file
RFC Doc Search

If we go down the list of packets I currently have in there:

  1. SNMP (Simple Network Management Protocol):
    • RFC 1157: A Simple Network Management Protocol (SNMP).
    • RFC 1905: Protocol Operations for SNMPv2.
    • RFC 2578: Structure of Management Information Version 2 (SMIv2).
    • RFC 3416: Version 2 of the Protocol Operations for the Simple Network Management Protocol (SNMP).

Theres pages for all of those, the one I actually found helpful for creating the packet, was https://datatracker.ietf.org/doc/html/rfc1592#section-3.1.1
Theres tables you'll see if you scroll

  1. DHCP (Dynamic Host Configuration Protocol):
    • RFC 2131: Dynamic Host Configuration Protocol.
    • RFC 2132: DHCP Options and BOOTP Vendor Extensions.

Helpful in creating the packet
https://datatracker.ietf.org/doc/rfc1541/ page 24 table

  1. NTP (Network Time Protocol):
    • RFC 5905: Network Time Protocol Version 4: Protocol and Algorithms Specification.

Stack Overflow source
image

  1. DNS (Domain Name System):
    • RFC 1035: Domain Names - Implementation and Specification.

Found this on some medium article, cause the datatracker docs is an insane read for my smoothed over brain
1_heEItB6nil3lq98Cg8EuWw (1)

TLDR The packets are a problem, creating them is a pain is was a mix of handwriting and copilot
Testing this stuff is also very tedious as, find an Ip with open UDP port, nmap -sU wait 10-30 minutes compare rustscan.
I will start to work on improving this, as I am still learning about this.

Better news, looking more into nmap they are actually just sending empty packets to most ports on UDP scans, crafting specific payloads for specific well known ports.
I will add that to the TODO list
Also this was helpful for the packets https://github.com/nmap/nmap/blob/master/nmap-service-probes but they have some kind of insane parser and my packets are probably wrong

If you get a chance to look over this, and want me to change other things besides packet generation I will get on that first.
Otherwise I'll work on improving and adding to the packet crafting, as what I have now is pretty terrible, but it kind of works based on what I have seen.

@bee-san
Copy link
Owner

bee-san commented May 26, 2024

find an Ip with open UDP port,

Hey, so I could actually deploy an AWS EC2 instance and run some stuff on Docker for you to test? Since it's EC2 I believe scannigng is ok, since I (the EC2 owner) will say it's okay 🤷🏻

Better news, looking more into nmap they are actually just sending empty packets to most ports on UDP scans, crafting specific payloads for specific well known ports.

This is cool! We have no service probing functionality yet for TCP or UDP :)

If you get a chance to look over this, and want me to change other things besides packet generation I will get on that first.

Sure, let me take a quick look :)

Copy link
Owner

@bee-san bee-san left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok heres some lil rust things :) hope that helps!

@bee-san
Copy link
Owner

bee-san commented May 26, 2024

Thank you SO much!! Such a great PR :) It is crazy you consider yourself a junior developer. I would not even expect this type of code from senior developers 😂

BrendanGlancy and others added 2 commits May 26, 2024 20:26
typo

Co-authored-by: Autumn (Bee) <github@skerritt.blog>
@BrendanGlancy
Copy link
Contributor Author

@bee-san This is like, in the direction of what you were suggesting.

I'm just not good enough at Rust currently to make payload generation that great. I'm pushing to work on this on a different PC and to "merge incomplete features and improve upon them rather than wait an infinite amount of time to have the most perfect feature " because there's a lot of TODOs that keep popping up with everything I add.

Thank you so much for all the help. It has made this super fun to work on, and I am learning a lot. I'd be interested in the EC2 thing unless it's going to cost you money.

As always, I'm going to continue to work on this. If you have any more suggestions, I'll work on those. I appreciate the input :)

@bee-san
Copy link
Owner

bee-san commented May 28, 2024

I'm just not good enough at Rust currently to make payload generation that great

Nonsense! This code looks fine to me :)

I'd be interested in the EC2 thing unless it's going to cost you money.

Will find time to do that :)

I have not read your updates yet but I did some reading.

I am thinking version 0.0.1 of this could just be the empty UDP packets like you talked about, and then we can add new packet types for specific things in the future. One per PR would be nice :)

A common pattern I do is to break the problem down and then build out the absolute minimum viable solution for it (in this case, just empty packets).

But I write the code anticipating the need that there will be more packets in the future.

However I think here it'll be ok to mostly not do that....

I am not sure how we'd match ports up to specific packets, we'd need a hashmap of port:function() 🤔

I am thinking:

  1. How can we get this merged now?
  2. How can we make it easier for people in the future to contribute their own UDP packets? If you make it as easy to contribute to as possible and you make GitHub issues for specific packets I am sure we will get some contributors weighing in :)

@BrendanGlancy
Copy link
Contributor Author

BrendanGlancy commented May 30, 2024

@bee-san

I am thinking version 0.0.1 of this could just be the empty UDP packets like you talked about, and then we can add new packet types for specific things in the future. One per PR would be nice :)

That is fine, that would just a matter of commenting out some code. When we UDP::bind then => Connect, std::net handles creating the UDP packet headers for us

pub fn custom_payload(dst_prt: u16) -> Vec<u8>{
    match dst_prt {
        // 53 => craft_dns_query_packet(),
        // 67 => craft_dhcpc_packet(),
        // 123 => craft_ntp_packet(),
        // 161 => craft_snmp_packet(),
        _ => vec![]
    }
}

I am not sure how we'd match ports up to specific packets, we'd need a hashmap of port:function() 🤔

Yes, I can start with the top 100.

I am thinking:

  1. How can we get this merged now?

I am not sure besides building what I mention below.

  1. How can we make it easier for people in the future to contribute their own UDP packets? If you make it as easy to contribute to as possible and you make GitHub issues for specific packets I am sure we will get some contributors weighing in :)

[https://nmap.org/book/nmap-payloads.html] I think having some kind of parser for something like this wouldn't be that difficult.

The more difficult part is building out some kind of library to make it easier to hard code these payloads, for example theres a bunch of different versions of SNMP payloads they all share the same structure.

IP-packet-encapsulation-of-SNMP-version-2c

I can begin to work on this. Also, I am probably reiterating stuff you already know, for the purpose of making it easier for me to keep track of TODOs on this feature.

@bee-san
Copy link
Owner

bee-san commented Jun 15, 2024

want me to review / merge?

@BrendanGlancy
Copy link
Contributor Author

@bee-san yeah sure!

Copy link
Collaborator

@PsypherPunk PsypherPunk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of minor quibbles with typos. and a couple of questions but this is very, very nice.

async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
let tries = self.tries.get();
if self.udp {
let waits = vec![0, 51, 107, 313];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: can I check where these values have come from?

Are they particularly meaningful? And worth documenting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, they were 50, 100, 300.

bee-san suggested

Suggestion: Make the times less even? A firewall would pick up on even timing. Ideally we'd use random times
but it's slow and should be in a --quiet option (one for another PR)
Just doing things like 0, 51, 107, 313 etc would be good :)

Would've never thought of this myself

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PsypherPunk Because of the way UDP works we don't know how long to wait to assume failure. Normally TCP would always get back to us, and if it doesn't we wait 1 second I think.

We need to tell UDP how long to wait for before moving on, I was thinking if we send multiple UDP packets at even timestamps the firewall would easily pick up on it. Uneven doesn't help so much but it's slightly better than nothing.

Something I realised is we have 0 here. Reading the code:

https://github.com/RustScan/RustScan/blob/52bfcf048db5e10bcdd887abb350c85606331760/src/scanner/mod.rs#L258

Does this imply we wait 0 seconds before assuming it's closed?
And thinking more about it do we need a vector of timeouts here at all?

The normal TCP scan waits 1.5 seconds:
https://github.com/RustScan/RustScan/blob/52bfcf048db5e10bcdd887abb350c85606331760/src/input.rs#L116

I think you should actually parse the timeout input down here and use that instead? That way in the future we can update this to a random timeout if we want to :)

Sorry, only just caught this 🙈

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes actually thinking about this more, there's other functions which use the timeout given at the argparsing level so I think we should not include this vector and just parse the timeout from the argparsing part (like the other tcp scanner does)

and I think a nice lil feature would be some code that can alter that timeout more in depth, like randomised timeouts

src/tui.rs Outdated
"I scanned ports so fast, even my computer was surprised.",
"RustScan: Where '404 Not Found' meets '200 OK'.",
"RustScan: Exploring the digital landscape, one IP at a time.",
"DeathStarMafia was here 🚀",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: is this suitable?

One for @bee-san: is this okay to add? Not sure there are other, named individuals/orgs. in this list…?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lol that's my CTF team (I did not name it), but I'll change this. But yes the 0day guy added himself to this but maybe he's an exception as he's tiktok famous

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realise "0day" was a person; thought it was a reference to the thing. Shows what I know.

Kudos on the CTF team name though.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PsypherPunk
@BrendanGlancy yes, 0day is one of my friends. his dog passed away sadly and i wanted to commemorate him (Ollie), 0day put in a PR to add his own name so I thought it'd be ok 😅

@BrendanGlancy I will let you add your name here if you add 3 more networking related / hacking jokes 😉

@bee-san
Copy link
Owner

bee-san commented Jun 24, 2024

@BrendanGlancy are you in my discord? http://discord.skerritt.blog

got an ec2 instance you can scan for udp but dont want to publish the IP to the public haha

@PsypherPunk
Copy link
Collaborator

PsypherPunk commented Jun 24, 2024

got an ec2 instance you can scan for udp but dont want to publish the IP to the public haha

FWIW, I've been spinning up a quick UDP socket via Python to test this (or at least making sure it picks up the right port):

import socket


UDP_IP = "127.0.0.1"
UDP_PORT = 5005

sock = socket.socket(
    socket.AF_INET,
    socket.SOCK_DGRAM,
)
sock.bind((UDP_IP, UDP_PORT))

while True:
    data, addr = sock.recvfrom(1024)
    print(f"Received message: {data}")

@BrendanGlancy
Copy link
Contributor Author

@bee-san Yes I just joined, but I already got in trouble with the mod. hopefully, I'll have a commit with the requested changes tonight

@PsypherPunk Sorry about all the typos, I've never had a real software engineering job where someone reviews my code I didn't realize I was that sloppy

Really appreciate all the feedback from the both of you :)

@bee-san
Copy link
Owner

bee-san commented Jun 24, 2024

@bee-san Yes I just joined, but I already got in trouble with the mod. hopefully, I'll have a commit with the requested changes tonight

@PsypherPunk Sorry about all the typos, I've never had a real software engineering job where someone reviews my code I didn't realize I was that sloppy

Really appreciate all the feedback from the both of you :)

@bee-san Yes I just joined, but I already got in trouble with the mod. hopefully, I'll have a commit with the requested changes tonight

@PsypherPunk Sorry about all the typos, I've never had a real software engineering job where someone reviews my code I didn't realize I was that sloppy

Really appreciate all the feedback from the both of you :)

Ahh it's okay! It's good code :) I really think that after you update it to use the timeout from the args we can get this merged, I see no other issues @PsypherPunk ?

@PsypherPunk
Copy link
Collaborator

Ahh it's okay! It's good code :) I really think that after you update it to use the timeout from the args we can get this merged, I see no other issues @PsypherPunk ?

One outstanding typo. in Recieved and I'm done 😁

@BrendanGlancy
Copy link
Contributor Author

@bee-san

Hopefully this is what you meant

    async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
        if self.udp {
            let payload = cust_payload(socket.port());

            let tries = self.tries.get();
            for _ in 1..=tries {
                match self.udp_scan(socket, &payload, self.timeout).await {
                    Ok(true) => return Ok(socket),
                    Ok(false) => continue,
                    Err(e) => return Err(e),
                }
            }
            return Ok(socket);
        }

@bee-san
Copy link
Owner

bee-san commented Jun 25, 2024

@bee-san

Hopefully this is what you meant

    async fn scan_socket(&self, socket: SocketAddr) -> io::Result<SocketAddr> {
        if self.udp {
            let payload = cust_payload(socket.port());

            let tries = self.tries.get();
            for _ in 1..=tries {
                match self.udp_scan(socket, &payload, self.timeout).await {
                    Ok(true) => return Ok(socket),
                    Ok(false) => continue,
                    Err(e) => return Err(e),
                }
            }
            return Ok(socket);
        }

Amazing!!

1 small thing, you have this:

tries

This looks like a user defined argument, but:

  1. I can't see any default for it
  2. I can't see it in the arguments

And I think it'd be better named something like udp_retries, to indicate its for retries specifically for udp :)

If I'm wrong let me know, it's early for me but this looks good!

Comment on lines +279 to +288
/// Formats and prints the port status
fn fmt_ports(&self, socket: SocketAddr) {
if !self.greppable {
if self.accessible {
println!("Open {socket}");
} else {
println!("Open {}", socket.to_string().purple());
}
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ticket to make in the future, we need to move all of this printing stuff into its own macro in the TUI file :)

@bee-san
Copy link
Owner

bee-san commented Jun 25, 2024

Ok, CI is failing the lint check and I'm wrong, we have tries here:
https://github.com/RustScan/RustScan/blob/cec858fc2d80dec786e9f1e3f95d740cdb018bc4/src/input.rs#L122

@bee-san
Copy link
Owner

bee-san commented Jun 25, 2024

ok for me just CI needs to pass and we can merge :)

CI runs cargo lint && cargo test && cargo clippy

if all 3 pass locally then you are good!

@bee-san bee-san merged commit f544f22 into bee-san:master Jun 25, 2024
@bee-san
Copy link
Owner

bee-san commented Jun 25, 2024

Wow! Crazy! UDP!!! 🥳 Merged!!!!

@BrendanGlancy
Copy link
Contributor Author

BrendanGlancy commented Jun 25, 2024

You both have been awesome to work with. Thank you

@bee-san
Copy link
Owner

bee-san commented Jun 25, 2024

@BrendanGlancy feel free to make more PRs, this was fantastic 🥳

@PsypherPunk PsypherPunk mentioned this pull request Aug 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants