Bug Nonties! Volume 1

AWS Security Groups

This is a series on practicing skills used to hunt for bugs, make the world a better place, and earn some coin. This series is by many accounts, a list of failures...since none of the things I write about were considered vulnerabilities or valid for fix. I did however gain some good-old lessons in how things work, and hopefully these lessons help expand your secure horizons as well, read on!

While writing a paper for school, I was researching the details of how security groups function in AWS. While sending packets from Scapy with a manipulated protocol field to personal EC2 instances, I noticed that a security group would allow outbound “ICMP protocol unreachable messages” to be sent from the instance, even when there was no outbound rule present to allow such messages. This appeared to be a break in the security group model* as traffic was allowed to egress without an explicit allow rule.  

Conditions 

  • The reflecting instance had no receiving application stack to accept the inbound protocol.
  • The reflecting instance’s Security Group had an ingress rule open for the protocol.
  • The reflecting instance’s Security Group only had one egress rule for TCP 22 to a /32.
  • The single /32 was only used for SSH administration.

Test Setup

I created a simple CloudFormation template to create/teardown a test environment quickly. That in itself was a valuable exercise.

Figure 1: TCP traffic without corresponding allow rule on reflector security group is blocked by the SG. Additionally, protocol 133, allowed on the inbound, leads to an "ICMP protocol unreachable" message despite having no allow rule.

With simple infrastructure readily available, I used Python and Scapy to send several requests at the test instance (named reflector). Here are the steps

  1. Note your administrative workstation's IP and validate the template.
    1. e.g. $> dig +short myip.opendns.com @resolver1.opendns.com.
    2. Examine Base64-encoded UserData within sgBypass.json.
  2. Import the sgBypass.json CFT into CloudFormation.
  3. Fill out the parameters, make sure to specify your workstations IP in the SGTightenParameter with a /32 if you want to be able to SSH into it.  
  4. (Optional) SSH into the “reflector” system and start listener for ICMP
    1. e.g. $> sudo tcpdump -ni eth0 icmp
  5. SSH into the “sender-listener” system 
  6. Make a new screen e.g.:
    1. $> screen
    2. $> ctrl + c 
  7. Start TCPDump
    1. $> sudo tcpdump -ni eth0 icmp
  8. On “sender-listener,” start scapy e.g.:
    1. $> ctrl + a 1 
    2. $> sudo scapy
  9. Craft and send the packet after updating the dst param with the ip of the reflector
    1.  send(IP(dst=“<reflector IP>”, proto=133)/TCP(sport=7357,dport=8090))
  10. Note the ICMP protocol unreachable errors received by “sender-listener” in spite of the restrictive/non-permissive security group. Note that the message was sent by the “reflector” host.

Sample tcpdump Logs retrieved from “Sending/Receiving” Instance (shows reflector returning ICMP messages)

  • IP 100.26.231.112 > IP 10.0.0.50: ICMP 100.26.231.112 protocol 5 unreachable, length 48
  • IP 100.26.231.112 > 10.0.0.50: ICMP 100.26.231.112 protocol 7 unreachable, length 48
  • IP 100.26.231.112 > 10.0.0.50: ICMP 100.26.231.112 protocol 8 unreachable, length 48

Additional Details

  • 248/254 protocols** led to an ICMP response being sent and successfully received despite no matching outbound rule in the Security Group.
  • There were seven protocols which were exceptions to this rule, and were blocked or did not lead to messages being sent: 2,6,17,41,58,103,136

Potential Threat Vectors

Per the AWS penetration testing policy*** no DoS testing or simulation was performed.

  • Denial of Service on 3rd party via spoofed source addresses.
  • Covert communications with other hosts (timing, protocol number, etc. of ICMP replies to spoofed source).

Key Take-aways

Working with the AWS vulnerability reporting team, I learned that this falls under expected behavior for a stateful firewall. However, I was left not fully understanding the differences in response across protocols which I observed. That is, when protocols 2, 6, 17, 41, 58,103 or 136 were included, there was no ICMP message.  I can see TCP, UDP and UDP light not generating ICMP messages because maybe they are common enough to have these protocol stacks preinstalled, but this doesn’t explain some of the more eclectic protocols.  I would have expected at least these to act consistently with the others if this were an issue of state. It seems perhaps, there are simply a few additional protocol stacks installed on EC2 than I realized.

This was a good learning lesson for me, however, as I had been under the impression state was a little more like Same Origin Policy. That is that protocol would be considered in determining state. But protocol is not considered in network state, so alas, this was chalked up to expected behavior.

In conclusion, if threat vectors like those explored above are abused someday in the future, enhancing network state by adding protocol to firewall logic would help prevent superfluous ICMP messages from being sent.


*https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml

**https://aws.amazon.com/security/penetration-testing/

***https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html