Merge pull request #22 from ivre/fix-http

Fix bug in HTTP FSM
This commit is contained in:
Pierre 2021-12-23 15:19:26 +01:00 committed by GitHub
commit ddfeb1461d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 85 additions and 0 deletions

View file

@ -232,6 +232,11 @@ pub fn repl<'a>(
debug!("pstate: {}", pstate.state); debug!("pstate: {}", pstate.state);
return None; return None;
} }
/* if not in CONTENT state, not responding yet (it means the client
* has not finished sending headers yet) */
if pstate.state != HTTP_STATE_CONTENT {
return None;
}
let content = "\ let content = "\
<html> <html>
<head><title>401 Authorization Required</title></head> <head><title>401 Authorization Required</title></head>

View file

@ -285,4 +285,34 @@ mod tests {
}; };
} }
} }
#[test]
fn test_proto_repl_http() {
/* ensure that HTTP FSM does not answer until completion of request
* (at least headers) */
let mut client_info = ClientInfo::new();
let test_ip_addr = Ipv4Addr::new(3, 2, 1, 0);
client_info.ip.src = Some(IpAddr::V4(test_ip_addr));
client_info.port.src = Some(65000);
let masscanned_ip_addr = Ipv4Addr::new(0, 1, 2, 3);
let mut ips = HashSet::new();
ips.insert(IpAddr::V4(masscanned_ip_addr));
/* Construct masscanned context object */
let masscanned = Masscanned {
synack_key: [0, 0],
mac: MacAddr::from_str("00:11:22:33:44:55").expect("error parsing MAC address"),
iface: None,
ip_addresses: Some(&ips),
};
/***** TEST COMPLETE REQUEST *****/
let payload = b"GET / HTTP/1.1\r\n\r\n";
if let None = repl(&payload.to_vec(), &masscanned, &mut client_info) {
panic!("expected an answer, got nothing");
}
/***** TEST INCOMPLETE REQUEST *****/
let payload = b"GET / HTTP/1.1\r\n";
if let Some(_) = repl(&payload.to_vec(), &masscanned, &mut client_info) {
panic!("expected no answer, got one");
}
}
} }

View file

@ -537,6 +537,56 @@ def test_ipv4_tcp_http():
assert tcp.payload.load.startswith(b"HTTP/1.1 401 Unauthorized\n") assert tcp.payload.load.startswith(b"HTTP/1.1 401 Unauthorized\n")
@test
def test_ipv4_tcp_http_incomplete():
sport = 24595
dports = [80, 443, 5000, 53228]
for dport in dports:
seq_init = int(RandInt())
syn = (
Ether(dst=MAC_ADDR)
/ IP(dst=IPV4_ADDR)
/ TCP(flags="S", sport=sport, dport=dport, seq=seq_init)
)
syn_ack = srp1(syn, timeout=1)
assert syn_ack is not None, "expecting answer, got nothing"
check_ip_checksum(syn_ack)
assert TCP in syn_ack, "expecting TCP, got %r" % syn_ack.summary()
syn_ack = syn_ack[TCP]
assert syn_ack.flags == "SA", "expecting TCP SA, got %r" % syn_ack.flags
ack = (
Ether(dst=MAC_ADDR)
/ IP(dst=IPV4_ADDR)
/ TCP(
flags="A",
sport=sport,
dport=dport,
seq=seq_init + 1,
ack=syn_ack.seq + 1,
)
)
_ = srp1(ack, timeout=1)
req = (
Ether(dst=MAC_ADDR)
/ IP(dst=IPV4_ADDR)
/ TCP(
flags="PA",
sport=sport,
dport=dport,
seq=seq_init + 1,
ack=syn_ack.seq + 1,
)
# purposedly incomplete request (missing additionnal ending \r\n)
/ Raw("GET / HTTP/1.1\r\n")
)
resp = srp1(req, timeout=1)
assert resp is not None, "expecting an answer, got none"
check_ip_checksum(resp)
assert TCP in resp, "expecting TCP, got %r" % resp.summary()
tcp = resp[TCP]
assert tcp.flags == "A", "expecting TCP flag A, got {}".format(tcp.flags)
@test @test
def test_ipv6_tcp_http(): def test_ipv6_tcp_http():
sport = 24592 sport = 24592