Skip to content

Commit

Permalink
new: added http.vhost virtual host enumeration
Browse files Browse the repository at this point in the history
  • Loading branch information
evilsocket committed Nov 13, 2023
1 parent 6438347 commit c5f6c71
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 7 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ For the building instructions, usage and the complete list of options [check the

## Supported Protocols/Features:

AMQP (ActiveMQ, RabbitMQ, Qpid, JORAM and Solace), Cassandra/ScyllaDB, DNS subdomain enumeration, FTP, HTTP (basic authentication, NTLMv1, NTLMv2, multipart form, custom requests with CSRF support and files/folders enumeration), IMAP, Kerberos pre-authentication and user enumeration, LDAP, MongoDB, MQTT, Microsoft SQL, MySQL, Oracle, PostgreSQL, POP3, RDP, Redis, SSH / SFTP, SMTP, STOMP (ActiveMQ, RabbitMQ, HornetQ and OpenMQ), TCP port scanning, Telnet, VNC.
AMQP (ActiveMQ, RabbitMQ, Qpid, JORAM and Solace), Cassandra/ScyllaDB, DNS subdomain enumeration, FTP, HTTP (basic authentication, NTLMv1, NTLMv2, multipart form, custom requests with CSRF support, files/folders enumeration, virtual host enumeration), IMAP, Kerberos pre-authentication and user enumeration, LDAP, MongoDB, MQTT, Microsoft SQL, MySQL, Oracle, PostgreSQL, POP3, RDP, Redis, SSH / SFTP, SMTP, STOMP (ActiveMQ, RabbitMQ, HornetQ and OpenMQ), TCP port scanning, Telnet, VNC.

## Benchmark

Expand Down
56 changes: 50 additions & 6 deletions src/plugins/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use async_trait::async_trait;
use ctor::ctor;
use rand::seq::SliceRandom;
use reqwest::{
header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE, COOKIE, USER_AGENT},
header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE, COOKIE, HOST, USER_AGENT},
multipart, redirect, Client, Method, RequestBuilder, Response,
};
use url::Url;
Expand All @@ -29,6 +29,7 @@ fn register() {
crate::plugins::manager::register("http.ntlm1", Box::new(HTTP::new(Strategy::NLTMv1)));
crate::plugins::manager::register("http.ntlm2", Box::new(HTTP::new(Strategy::NLTMv2)));
crate::plugins::manager::register("http.enum", Box::new(HTTP::new(Strategy::Enumeration)));
crate::plugins::manager::register("http.vhost", Box::new(HTTP::new(Strategy::VHostEnum)));
}

fn method_requires_payload(method: &Method) -> bool {
Expand All @@ -43,6 +44,7 @@ pub(crate) enum Strategy {
NLTMv1,
NLTMv2,
Enumeration,
VHostEnum,
}

struct Success {
Expand Down Expand Up @@ -404,6 +406,47 @@ impl HTTP {
}
}
}

async fn http_vhost_enum_attempt(
&self,
creds: &Credentials,
timeout: Duration,
) -> Result<Option<Loot>, Error> {
let url = self.get_target_url(&creds.target)?;
let mut headers = self.setup_headers();

// set host
headers.remove(HOST);
headers.insert(HOST, HeaderValue::from_str(&creds.username).unwrap());

// build base request object
let request = self
.client
.request(self.method.clone(), &url)
.headers(headers)
.timeout(timeout);

// execute
match request.send().await {
Err(e) => Err(e.to_string()),
Ok(res) => {
if let Some(success) = self.is_success(res).await {
Ok(Some(Loot::new(
"http.vhost",
&creds.target,
[
("vhost".to_owned(), creds.username.to_owned()),
("status".to_owned(), success.status.to_string()),
("size".to_owned(), success.content_length.to_string()),
("type".to_owned(), success.content_type),
],
)))
} else {
Ok(None)
}
}
}
}
}

#[async_trait]
Expand All @@ -416,11 +459,12 @@ impl Plugin for HTTP {
Strategy::NLTMv1 => "NTLMv1 authentication over HTTP.",
Strategy::NLTMv2 => "NTLMv2 authentication over HTTP.",
Strategy::Enumeration => "HTTP pages enumeration.",
Strategy::VHostEnum => "HTTP virtual host enumeration.",
}
}

fn single_credential(&self) -> bool {
self.strategy == Strategy::Enumeration
matches!(self.strategy, Strategy::Enumeration | Strategy::VHostEnum)
}

fn setup(&mut self, opts: &Options) -> Result<(), Error> {
Expand Down Expand Up @@ -545,10 +589,10 @@ impl Plugin for HTTP {
}

async fn attempt(&self, creds: &Credentials, timeout: Duration) -> Result<Option<Loot>, Error> {
if self.strategy == Strategy::Enumeration {
self.http_enum_attempt(creds, timeout).await
} else {
self.http_request_attempt(creds, timeout).await
match self.strategy {
Strategy::Enumeration => self.http_enum_attempt(creds, timeout).await,
Strategy::VHostEnum => self.http_vhost_enum_attempt(creds, timeout).await,
_ => self.http_request_attempt(creds, timeout).await,
}
}
}
Expand Down
26 changes: 26 additions & 0 deletions test-servers/http-vhost-public.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
server {
listen [::]:80;
listen 80;
server_name public.company.com;

sendfile off;
tcp_nodelay on;
absolute_redirect off;
access_log off;
error_log off;

root /var/www/html;
index index.html;

# Redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}

# Deny access to . files, for security
location ~ /\. {
log_not_found off;
deny all;
}
}
26 changes: 26 additions & 0 deletions test-servers/http-vhost-secret.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
server {
listen [::]:80;
listen 80;
server_name internal.company.com;

sendfile off;
tcp_nodelay on;
absolute_redirect off;
access_log off;
error_log off;

root /var/www/secret;
index index.html;

# Redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /var/lib/nginx/html;
}

# Deny access to . files, for security
location ~ /\. {
log_not_found off;
deny all;
}
}
1 change: 1 addition & 0 deletions test-servers/http-vhost.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Public vhost
7 changes: 7 additions & 0 deletions test-servers/http-vhost.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
clear && docker run \
-p 8888:80 \
-v `pwd`/http-vhost:/var/www/secret \
-v `pwd`/http-vhost.html:/var/www/html/index.html \
-v `pwd`/http-vhost-public.conf:/etc/nginx/conf.d/public.conf \
-v `pwd`/http-vhost-secret.conf:/etc/nginx/conf.d/secret.conf \
trafex/php-nginx
1 change: 1 addition & 0 deletions test-servers/http-vhost/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Secret internal vhost!

0 comments on commit c5f6c71

Please sign in to comment.