mirror of
https://github.com/onionltd/EndGame.git
synced 2024-10-01 04:15:36 -04:00
Add EndGame version 2
This commit is contained in:
parent
770d6da100
commit
4a766ef0ac
8
.idea/endgame.iml
Normal file
8
.idea/endgame.iml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/endgame.iml" filepath="$PROJECT_DIR$/.idea/endgame.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
39
.idea/workspace.xml
Normal file
39
.idea/workspace.xml
Normal file
@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="29df5c5c-3c59-4700-af86-2362f0062d00" name="Default Changelist" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/site.conf" beforeDir="false" afterPath="$PROJECT_DIR$/site.conf" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="GOROOT" path="$USER_HOME$/.gvm/gos/go1.14" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1l8K8ywGwL2SwuuTElCHEoZyLHy" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="go.import.settings.migrated" value="true" />
|
||||
<property name="go.sdk.automatically.set" value="true" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/../docker-tor-hidden-service" />
|
||||
<property name="settings.editor.selected.configurable" value="ide.date.format" />
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="WindowStateProjectService">
|
||||
<state x="473" y="214" key="FileChooserDialogImpl" timestamp="1607015731915">
|
||||
<screen x="0" y="0" width="1368" height="768" />
|
||||
</state>
|
||||
<state x="473" y="214" key="FileChooserDialogImpl/0.0.1368.768@0.0.1368.768" timestamp="1607015731915" />
|
||||
<state x="380" y="251" width="616" height="512" key="find.popup" timestamp="1606975273843">
|
||||
<screen x="0" y="0" width="1368" height="768" />
|
||||
</state>
|
||||
<state x="380" y="251" width="616" height="512" key="find.popup/0.0.1368.768@0.0.1368.768" timestamp="1606975273843" />
|
||||
</component>
|
||||
</project>
|
File diff suppressed because it is too large
Load Diff
24
LOOKHERE-scripts/onionbalance/README.MD
Normal file
24
LOOKHERE-scripts/onionbalance/README.MD
Normal file
@ -0,0 +1,24 @@
|
||||
Onionbalance is the core of your scalability system. This is what makes all your seperate front onions work as a unified front!
|
||||
|
||||
However it has it's limits. Onion Services have a limit to the amount of introduction points within a specific descriptor they can have and how large the descriptor can be.
|
||||
|
||||
These limits lead to some pretty big problems.
|
||||
|
||||
1) There is a limit to the amount of fronts a single onion can have.
|
||||
2) Each front can only have a certain amount of introduction points themselves.
|
||||
3) Under attack descriptors can become spent before they can be replaced.
|
||||
|
||||
"spent" descriptors are when all the introduction points to the onion service are no longer accepting clients. Introduction points have a certain amount of introduction cell requests it will accept before not accepting anymore. These requests are the Tor's main DDOS problem. By specifically requesting tons of introduction cells, which are computationally cheap to do, an attacker can overload an onion service. The only way to protect against this right now is by scaling out.
|
||||
|
||||
First read the README.MD from the main directory and install onionbalance to a 2CPU 2GB RAM server seperate from your cluster of fronts.
|
||||
|
||||
After you have installed onionbalance you will need to cd into the directory go to /onionbalance/hs_v3/params.py and change
|
||||
N_INTROS_PER_INSTANCE = 2 -> N_INTROS_PER_INSTANCE = 1
|
||||
|
||||
Save the params.py file and go back to the main onionbalance directory. Run
|
||||
|
||||
python3 setup.py install
|
||||
|
||||
and then you can setup the configuration
|
||||
|
||||
**When setting up your onionbalance configuration limit the amount of fronts to 18! Setting it higher you can get descriptor or introduction issues which will cause your onion's descriptor to not be correctly pushed.**
|
@ -24,7 +24,7 @@ service tor stop
|
||||
rm /etc/tor/torrc
|
||||
mv torrc /etc/tor/torrc
|
||||
|
||||
git clone https://gitlab.torproject.org/asn/onionbalance.git
|
||||
git clone https://github.com/zscole/onionbalance.git
|
||||
cd onionbalance
|
||||
python3 setup.py install
|
||||
|
72
README.MD
72
README.MD
@ -1,27 +1,47 @@
|
||||
# EndGame - Onion Service DDOS Prevention Front System
|
||||
# EndGame V2 - Onion Service DDOS Prevention Front System
|
||||
|
||||
Provided by [Dread](http://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/) and [White House Market](http://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/d/WhiteHouseMarket). With help from [Big Blue Market](http://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/d/BigBlueMarket) and [Empire Market](dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/d/EmpireMarket).
|
||||
V2 Provided by [Dread](http://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/) and [White House Market](http://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion/d/WhiteHouseMarket).
|
||||
|
||||
**Should be used with this [onionbalance](https://github.com/zscole/onionbalance) process for distinct descriptors. Use one onion for everything.**
|
||||
|
||||
EndGame is
|
||||
|
||||
- a front system designed to protect the core application servers on an onion service in a safe and private way.
|
||||
- locally complied and locally run (no trusted or middle party).
|
||||
- a combination of multiple different technologies working together in harmony (listed below).
|
||||
- FREE FOR ALL TO USE!
|
||||
- *arguably* magic ㄟ( ▔, ▔ )ㄏ
|
||||
- a front system designed to protect the core application servers on an onion service in a safe and private way.
|
||||
- locally complied and locally run (no trusted or middle party).
|
||||
- a combination of multiple different technologies working together in harmony (listed below).
|
||||
- FREE FOR ALL TO USE!
|
||||
- *arguably* magic ㄟ( ▔, ▔ )ㄏ
|
||||
|
||||
# Main Features
|
||||
|
||||
- Fully scripted and easily deploy-able (for mass scaling!) on blank Debian 10 systems.
|
||||
- Full featured NGINX LUA script to filter packets and provide a captcha directly using the NGINX layer.
|
||||
- Rate limiting via Tor's V3 onion service circuit ID system with secondary rate limiting based on a testcookie like system.
|
||||
- Easy Configuration for both local and remote (over Tor) front systems.
|
||||
- Easily configurable and change-able to meet an onion service's needs.
|
||||
- Fully scripted and easily deploy-able (for mass scaling!) on blank Debian 10 systems.
|
||||
- Full featured NGINX LUA script to filter packets and provide a captcha directly using the NGINX layer.
|
||||
- Rate limiting via Tor's V3 onion service circuit ID system with secondary rate limiting based on a testcookie like system.
|
||||
- Easy Configuration for both local and remote (over Tor) front systems.
|
||||
- Easily configurable and change-able to meet an onion service's needs.
|
||||
|
||||
It can also:
|
||||
- Cause you to grow a bigger dick than the asshole DDOSER (true *figurally*, lies *probably*)
|
||||
- Save you millions of dollars do to DDOSER's downing your site for ransom or for their extorting fees.
|
||||
- Make it look like you know what the fuck you are doing.
|
||||
- Cause you to grow a bigger dick than the asshole DDOSER (true *figurally*, lies *probably*)
|
||||
- Save you millions of dollars do to DDOSER's downing your site for ransom or for their extorting fees.
|
||||
- Make it look like you know what the fuck you are doing.
|
||||
|
||||
# V2 Updates
|
||||
V2 EndGame has updates to the broken captcha generation process using a clock facing captcha. It includes extra features like
|
||||
- updated documentation
|
||||
- load balanced Tor socks processes for more stable socks_passes
|
||||
- unix listening instead of ports for performance, stability, and security
|
||||
- true randomization for captcha and cookie generation
|
||||
- simple queue system (time based, read below)
|
||||
- various theme configuration options right on the setup file
|
||||
- dependency script to get all the dependencies only once. Effectively snapshotting all dependencies preventing future dependency repo exploits in the VERY unlikely case a repo was to get compromised. Paranoia mode.
|
||||
- bug fixes and various performance tunings
|
||||
|
||||
### Notes About Queue System
|
||||
|
||||
V2 introduces a queue system which effectively prevents CPU exhaustion from mass get attacks. The clock captcha generation is computationally intensive and specifically vulnerable to this kind of attack. By limiting the amount of connections and amount of captcha tries it greatly reduces the CPU cycles to handle the attack.
|
||||
|
||||
In this version there is a simple time on line 110 of the `lua/cap.lua` file which gets checked on line 143. It is recommended to variate this value by attaching a sliding scale time circumstance base on front CPU load. Exponential functions based on the "/proc/stat" value. If you do that, keep the curve private because there is always an "ideal" attack value.
|
||||
When you set set the time value update the `queue.html` file via a script to rewrite the meta refresh variable.
|
||||
|
||||
### Tech Overview
|
||||
|
||||
@ -51,7 +71,7 @@ Libraries:
|
||||
* [LUA Resty Cookie](https://github.com/cloudflare/lua-resty-cookie) - Provides cookie manipulation
|
||||
* [LUA Resty Session](https://github.com/bungle/lua-resty-session) - Provides session manipulation
|
||||
* [LUA Resty AES](https://github.com/c64bob/lua-resty-aes/raw/master/lib/resty/aes_functions.lua) - AES Functions file for LUA. Used for shared session cookies.
|
||||
* [LUA GD](https://github.com/ittner/lua-gd/) - GD image generation bindings For LUA
|
||||
* [LUA Resty Random](https://github.com/bungle/lua-resty-random) - A *true* random number library for OpenResty.
|
||||
|
||||
### Configuration
|
||||
|
||||
@ -64,17 +84,23 @@ There are options. Such as:
|
||||
* TORAUTHPASSWORD - Password which is used for your Tor Control Port Authentication with NGINX. Alphanumeric without spaces (example: passwordIcanremembertyping)
|
||||
* KEY - Alphanumeric Key for the shared front session key. Random between 64-128 would do fine. (example: isthis64charactorsalreadyicantbelieveitwowsocoolwaitnotyetohdarn)
|
||||
* SALT - 8 character salt used with the key. 8 random alphanumeric characters (example: saltsalt)
|
||||
* SESSION_LENGTH - In seconds the amount of time until cookie timeout. Set it high as you can. (example: 3600 [aka 1 hour])
|
||||
* HEXCOLOR - HEX color put into the css file to be not purple but your main site's color. Any CSS hex will work. (example: #9b59b6)
|
||||
* SITENAME - Site name automatically put in the captcha html file. (example: dread)
|
||||
* LOCALPROXY - If true will set proxy_pass url to the PROXYPASSURL and disable load balanced Tor processes. If enabled will take the BACKENDONIONURL and configure load balanced socks_pass. It's highly recommended to proxy locally if possible.
|
||||
* PROXYPASSURL - The local url used to proxy_pass all good connections. Not used if LOCALPROXY set to false.
|
||||
* BACKENDONIONURL - The remote onion service endpoint. This onion is not public and should have no rate limiting or filtering on it. Generally the "core" server onion. Not used if LOCALPROXY set to true.
|
||||
|
||||
There is also some editing you need to do in the `caphtml_d.lua`, `naxsi_whitelist.rules`, `site.conf`, and `torrc` files.
|
||||
|
||||
- `resty/caphtml_d.lua` - Two Base64 Images. The favicon (line 143) and main logo (line 162). You can use [this](https://base64.guru/converter/encode/image/ico) for the favicon and [this](https://base64.guru/converter/encode/image) for the main logo.
|
||||
- `queue.html` - Two base64 images. Search for <link href=" for the favicon and .logobgimg for the main logo. Update accordingly.
|
||||
- `naxsi_whitelist.rules` - NAXSI's Whitelist Rules with some internal rules [see this](https://github.com/nbs-system/naxsi/wiki/internal-rules). To be configured for your specific application's use case.
|
||||
- `site.conf` - Line 110 and 111 has the two rate limiting EndGame does. One by the circuit ID and one by the cookie. Depending on how your site calls files you may need to change these values.
|
||||
- Defaulty set to 3 consistent on line 110 and 111. 110 for circuit. 111 for cookie.
|
||||
- Line 245 has a nodelay burst of 6 for the circuit. Line 251 has a nodelay burst of 6 for the cookie.
|
||||
- Line 268-272 socks proxy_pass system. If you want EndGame to pass the filtered request over Tor you uncomment the socks_* lines and change the exampleprivatev3onion.onion to your core webserver's private v3 address.
|
||||
- Line 273 regular proxy_pass. If you have a secure local connection you want to use the regular proxy_pass for reliability and latency improvements. Just change it to your core webserver's private IP.
|
||||
- `site.conf` - Line 114 and 115 has the two rate limiting EndGame does. One by the circuit ID and one by the cookie. Depending on how your site calls files you may need to change these values.
|
||||
- Defaulty set to 6 consistent on line 114 and 115. 114 for circuit. 115 for cookie.
|
||||
- Line 263 has a nodelay burst of 10 for the circuit. Line 269 has a nodelay burst of 10 for the cookie.
|
||||
- Line 288-293 socks proxy_pass system. If you want EndGame to pass the filtered request over Tor you uncomment the socks_* lines and change the BACKENDONIONURL variable in the setup.sh file to your core webserver's private v3 address. If you do this you will need to comment the proxy_pass.
|
||||
- Line 273 regular proxy_pass. If you have a secure local connection you want to use the regular proxy_pass for reliability and latency improvements. Just change it to your core webserver's private IP. This is set as the default for performance reasons.
|
||||
- `torrc` - Depending on what you set your burst as change the HiddenServiceMaxStreams value to that plus 2.
|
||||
|
||||
### Setup Process
|
||||
@ -97,7 +123,7 @@ After the files are transferred make the setup.sh file executable and run it wit
|
||||
|
||||
##### STEP 4:
|
||||
|
||||
Scale out. Without scaling out you are bring a knife to a gun fight. At minimum you need 3 fronts. Onionbalance v3 doesn't have distinct descriptors which means if you go past about 6-9 fronts there might be some descriptor sizing issues on the default onionbalance setup. Endgame does make it much harder to take you down but you need to scale to keep up. Otherwise your front's Tor will get overloaded and you will go down. It's a dick measuring contest between you and the attacker. By scaling out you are effectively adding more length to your dick.
|
||||
Scale out. Without scaling out you are bring a knife to a gun fight. At minimum you need 3 fronts. Onionbalance v3 does have distinct descriptors now. You can scale to the moon and back. Endgame does make it much harder to take you down but you need to scale to keep up. Otherwise your front's Tor will get overloaded and you will go down. It's a dick measuring contest between you and the attacker. By scaling out you are effectively adding more length to your dick.
|
||||
|
||||
##### STEP 5:
|
||||
|
||||
@ -107,4 +133,4 @@ After scaling out with multiple fronts add all their onion addresses to onionbal
|
||||
|
||||
EndGame isn't perfect. It can't protect against introduction cell type attacks (the Tor project will need to add POW at the introduction points to fix that). But it does provide good protection and scaling which makes it much harder to take you down overall for whatever people throw at you.
|
||||
|
||||
This all is a major step forward for the darknet community. Never give in to the extorting DDOSERS. You are only paying to be attacked with more power in the future. Instead stand together and say "NO". As a united front we will reach heights never seen before.
|
||||
This all is a major step forward for the darknet community. Never give in to the extorting DDOSERS. You are only paying to be attacked with more power in the future. Instead stand together and say "NO". As a united front we will reach heights never seen before. 탈
|
321
cap_d.css
321
cap_d.css
@ -1,3 +1,320 @@
|
||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}strong{font-weight:bold}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0}*:focus{outline:0}input,select,textarea{border:0;box-shadow:0}html{height:100%}body{height:100%;line-height:1;background:#1A1E23;font-family:roboto, helvetica, sans-serif, arial, verdana, tahoma;font-size:16px;color:#fff}.container{width:100%;margin:0 auto;min-height:100%;position:relative;max-height:100vh;overflow:hidden}.container>.inner{position:absolute;top:50%;left:0;right:0;margin:0 auto;text-align:center;-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%);transform:translateY(-50%);}.container>.inner>.logo{display:inline-block;vertical-align:middle;text-decoration:none;margin-bottom:10px}.container>.inner>.logo>.square{display:inline-block;vertical-align:middle;width:40px;height:40px;background-color:HEXCOLOR;background-size:24px 24px;background-position:center center;background-repeat:no-repeat;margin-right:10px}.container>.inner>.logo>.text{display:inline-block;vertical-align:middle;font-size:30px;color:#fff;font-weight:700}.container>.inner>.date{display:block;text-align:center;font-size:42px}.container>.inner>.date>.day{color:HEXCOLOR;font-weight:bold}.signed{display:block;width:400px;height:150px;margin-top:20px;margin:20px auto 0 auto;}.signed>textarea{margin:0 auto;width:400px;height:150px;min-width:400px;max-width:400px;display:block;padding:15px;background:#fff;border:1px solid HEXCOLOR;min-height:150px;max-height:150px;}p{margin:0 auto 20px auto;max-width:300px;}form.ddos_form .captcha-input{margin:0 auto 20px auto;display: block;width:300px;font-size:0;}form.ddos_form .captcha-input input{display:inline-block;vertical-align:top;height:50px;width:calc(100% - 150px);outline:0;border:none;font-size:16px;color:#000;padding:0 15px;line-height:50px;}form.ddos_form .captcha-input img{display:inline-block;vertical-align:top;}form.ddos_form button{border-radius:3px;display:block;width:300px;margin:0 auto;background:HEXCOLOR;cursor:pointer;color:#fff;font-size:16px;text-transform:uppercase;text-align:center;height:40px;line-height:40px;outline:0;border:none;}
|
||||
.captchav2 {text-align: center;width: 100%;}.captchav2 > .imgWrap {display: inline-block;vertical-align: middle;width: 150px;height: 150px;background-size: cover;background-position: center center;}.captchav2 > .inputWrap {display: inline-block;vertical-align: middle;width: 120px;height: 120px;position: relative;margin-left: 15px;}.captchav2 > .inputWrap > div {position: absolute;width: 30px;height: 30px;cursor: pointer;border-radius: 100%;border: 2px solid #fff;} .captchav2 > .inputWrap > div.c1 { top: 0; left: 0; }.captchav2 > .inputWrap > div.c2 { top: 0; left: 0; right: 0; margin: 0 auto; }.captchav2 > .inputWrap > div.c3 { top: 0; right: 0; } .captchav2 > .inputWrap > div.c4 { top: 50%; left: 0; margin-top: -15px; }.captchav2 > .inputWrap > div.c5 { top: 50%; left: 0; right: 0; margin: -15px auto 0 auto; }.captchav2 > .inputWrap > div.c6 { top: 50%; right: 0; margin-top: -15px; } .captchav2 > .inputWrap > div.c7 { bottom: 0; left: 0; }.captchav2 > .inputWrap > div.c8 { bottom: 0; left: 0; right: 0; margin: 0 auto; }.captchav2 > .inputWrap > div.c9 { bottom: 0; right: 0; } .captchav2 > .inputWrap > input[type="checkbox"] {opacity: 0;margin: 0;padding: 0;cursor: pointer;position: absolute;width: 30px;height: 30px;z-index: 5;}.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(1) { top: 0; left: 0; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(1):checked ~ .c1 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(2) { top: 0; left: 0; right: 0; margin: 0 auto; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(2):checked ~ .c2 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(3) { top: 0; right: 0; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(3):checked ~ .c3 { background: #fff; } .captchav2 > .inputWrap > input[type="checkbox"]:nth-child(4) { top: 50%; left: 0; margin-top: -15px; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(4):checked ~ .c4 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(5) { top: 50%; left: 0; right: 0; margin: -15px auto 0 auto; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(5):checked ~ .c5 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(6) { top: 50%; right: 0; margin-top: -15px; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(6):checked ~ .c6 { background: #fff; } .captchav2 > .inputWrap > input[type="checkbox"]:nth-child(7) { bottom: 0; left: 0; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(7):checked ~ .c7 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(8) { bottom: 0; left: 0; right: 0; margin: 0 auto; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(8):checked ~ .c8 { background: #fff; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(9) { bottom: 0; right: 0; }.captchav2 > .inputWrap > input[type="checkbox"]:nth-child(9):checked ~ .c9 { background: #fff; }
|
||||
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}
|
||||
strong{font-weight:bold}
|
||||
body{line-height:1}ol,ul{list-style:none}
|
||||
blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}
|
||||
table{border-collapse:collapse;border-spacing:0}*:focus{outline:0}input,select,textarea{border:0;box-shadow:0}
|
||||
html{height:100%}body{height:100%;line-height:1;background:#1A1E23;
|
||||
font-family:roboto, helvetica, sans-serif, arial, verdana, tahoma;font-size:16px;color:#fff}
|
||||
.container {width:100%;margin:0 auto;min-height:100%;position:relative;max-height:100vh;overflow:hidden; }
|
||||
.container>.inner{position:absolute;top:50%;left:0;right:0;margin:0 auto;text-align:center;-webkit-transform:translateY(-50%);-moz-transform:translateY(-50%); transform:translateY(-50%);}
|
||||
.container>.inner>.logo{display:inline-block;vertical-align:middle;text-decoration:none;margin-bottom:10px}
|
||||
.container>.inner>.logo>.square{display:inline-block;vertical-align:middle;width:40px;height:40px;background-color:#9b59b6;background-size:24px 24px;background-position:center center;background-repeat:no-repeat;margin-right:10px}
|
||||
.container>.inner>.logo>.text{display:inline-block;vertical-align:middle;font-size:30px;color:#fff;font-weight:700}.container>.inner>.date{display:block;text-align:center;font-size:42px}
|
||||
.container>.inner>.date>.day{color:#9b59b6;font-weight:bold}.signed{display:block;width:400px;height:150px;margin-top:20px;margin:20px auto 0 auto;}
|
||||
.signed>textarea {margin:0 auto;width:400px;height:150px;min-width:400px;max-width:400px;display:block;padding:15px;background:#fff;border:1px solid #9b59b6;min-height:150px;max-height:150px;}p{margin:0 auto 20px auto;max-width:300px;}form.ddos_form .captcha-input{margin:0 auto 20px auto;display: block;width:300px;font-size:0;}form.ddos_form .captcha-input input{display:inline-block;vertical-align:top;height:50px;width:calc(100% - 150px);outline:0;border:none;font-size:16px;color:#000;padding:0 15px;line-height:50px;}form.ddos_form .captcha-input img{display:inline-block;vertical-align:top;}form.ddos_form button{border-radius:3px;display:block;width:300px;margin:0 auto;background:#9b59b6;cursor:pointer;color:#fff;font-size:16px;text-transform:uppercase;text-align:center;height:40px;line-height:40px;outline:0;border:none;}
|
||||
|
||||
.captchav2 {text-align: center;width: 100%;}
|
||||
|
||||
.captchav2 > .imgWrap {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
width: 195px;
|
||||
height: 195px;
|
||||
z-index: 4;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
transition: transform .5s ease;
|
||||
}
|
||||
|
||||
.captchav2 > .inputWrap {text-align: center; display:inline-block;vertical-align: middle;width: 184px;height: 184px;position: relative;margin-left: 0px; transition: transform .5s ease; }
|
||||
.captchav2 > .inputWrap > div {position: absolute;width: 60px;height: 60px;cursor: pointer;border-radius: 100%;border: 2px solid #fff;}
|
||||
|
||||
|
||||
.expire {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
position: relative;
|
||||
background: #888;
|
||||
animation: timer-warning 1s 1;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 50s;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.expire>.timer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper:first-child:after {
|
||||
content: ':';
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 15px;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
text-align: center;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
width: 15px;
|
||||
position: relative;
|
||||
animation: timer-expire;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 60s;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part>.digit-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part>.digit-wrapper>.digit {
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part.seconds.tens>.digit-wrapper {
|
||||
top: -50px;
|
||||
animation: timer-seconds-tens 50s 1;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 1s;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part.seconds.ones>.digit-wrapper {
|
||||
animation: timer-seconds-ones 10s 6;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part.hundredths.tens>.digit-wrapper {
|
||||
animation: timer-seconds-ones 1s 60;
|
||||
}
|
||||
|
||||
.expire>.timer>.time-part-wrapper>.time-part.hundredths.ones>.digit-wrapper {
|
||||
animation: timer-seconds-ones 500ms 120;
|
||||
}
|
||||
|
||||
@-webkit-keyframes timer-seconds-tens {
|
||||
0% {
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
19% {
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
20% {
|
||||
top: -100px;
|
||||
}
|
||||
|
||||
39% {
|
||||
top: -100px;
|
||||
}
|
||||
|
||||
40% {
|
||||
top: -150px;
|
||||
}
|
||||
|
||||
59% {
|
||||
top: -150px;
|
||||
}
|
||||
|
||||
60% {
|
||||
top: -200px;
|
||||
}
|
||||
|
||||
79% {
|
||||
top: -200px;
|
||||
}
|
||||
|
||||
80% {
|
||||
top: -250px;
|
||||
}
|
||||
|
||||
99% {
|
||||
top: -250px;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: -300px;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes timer-seconds-ones {
|
||||
0% {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
9% {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
10% {
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
19% {
|
||||
top: -50px;
|
||||
}
|
||||
|
||||
20% {
|
||||
top: -100px;
|
||||
}
|
||||
|
||||
29% {
|
||||
top: -100px;
|
||||
}
|
||||
|
||||
30% {
|
||||
top: -150px;
|
||||
}
|
||||
|
||||
39% {
|
||||
top: -150px;
|
||||
}
|
||||
|
||||
40% {
|
||||
top: -200px;
|
||||
}
|
||||
|
||||
49% {
|
||||
top: -200px;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: -250px;
|
||||
}
|
||||
|
||||
59% {
|
||||
top: -250px;
|
||||
}
|
||||
|
||||
60% {
|
||||
top: -300px;
|
||||
}
|
||||
|
||||
69% {
|
||||
top: -300px;
|
||||
}
|
||||
|
||||
70% {
|
||||
top: -350px;
|
||||
}
|
||||
|
||||
79% {
|
||||
top: -350px;
|
||||
}
|
||||
|
||||
80% {
|
||||
top: -400px;
|
||||
}
|
||||
|
||||
89% {
|
||||
top: -400px;
|
||||
}
|
||||
|
||||
90% {
|
||||
top: -450px;
|
||||
}
|
||||
|
||||
99% {
|
||||
top: -450px;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: -500px;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes timer-warning {
|
||||
from {
|
||||
background: #1A1E23;
|
||||
}
|
||||
|
||||
to {
|
||||
background: #E7943C;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes timer-expire {
|
||||
from {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
to {
|
||||
color: #e7643c;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes button-expired {
|
||||
from {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
to {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes button-before {
|
||||
from {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
to {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
select {
|
||||
font-size: 18px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 0 10px;
|
||||
height: 30px;
|
||||
line-height: 40px;
|
||||
color: #ffffe9;
|
||||
background: #1a1e23;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
form.ddos_form button.before {
|
||||
animation: button-before;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 60s;
|
||||
}
|
||||
|
||||
form.ddos_form button.expired {
|
||||
visibility: hidden;
|
||||
background: #E74C3C;
|
||||
animation: button-expired;
|
||||
animation-fill-mode: forwards;
|
||||
animation-delay: 60s;
|
||||
margin-top: -40px;
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
#!/usr/bin/python3 -u
|
||||
|
||||
from PIL import Image
|
||||
from PIL import ImageDraw
|
||||
from PIL import ImageFont
|
||||
import random
|
||||
import os
|
||||
|
||||
|
||||
def generate_background():
|
||||
random.seed()
|
||||
unicode_chars = (
|
||||
"\u2605",
|
||||
"\u2606",
|
||||
"\u2663",
|
||||
"\u2667",
|
||||
"\u2660",
|
||||
"\u2664",
|
||||
"\u2662",
|
||||
"\u2666",
|
||||
"\u263a",
|
||||
"\u263b",
|
||||
"\u26aa",
|
||||
"\u26ab",
|
||||
"\u2b53",
|
||||
"\u2b54",
|
||||
"\u2b00",
|
||||
"\u2b08",
|
||||
"\u2780",
|
||||
"\u278a",
|
||||
"\u267c",
|
||||
"\u267d",
|
||||
"\u25b2",
|
||||
"\u25b3",
|
||||
)
|
||||
|
||||
unicode_max = len(unicode_chars)
|
||||
try:
|
||||
for i in range(0, 25):
|
||||
im_cropped = Image.new('RGB', (150, 150),
|
||||
(random.randrange(120, 255), random.randrange(120, 255), random.randrange(120, 255)))
|
||||
origwidth, origheight = im_cropped.size
|
||||
|
||||
watermark = Image.new("RGBA", im_cropped.size)
|
||||
waterdraw = ImageDraw.ImageDraw(watermark, "RGBA")
|
||||
number_of_shapes = random.randrange(10, 15)
|
||||
for step in range(0, number_of_shapes):
|
||||
fillcolor = (
|
||||
random.randrange(0, 255), random.randrange(0, 255), random.randrange(0, 255),
|
||||
random.randrange(240, 255))
|
||||
u_char = unicode_chars[random.randrange(0, unicode_max)]
|
||||
font = ImageFont.truetype("/etc/nginx/font.ttf", random.randrange(25, 30))
|
||||
waterdraw.text((random.randrange(-10, 130), random.randrange(-10, 130)), u_char, fill=fillcolor, font=font)
|
||||
im_cropped.paste(watermark, None, watermark)
|
||||
im_cropped.save("/tmp/background-" + str(i) + '.jpg', format="JPEG")
|
||||
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
|
||||
generate_background()
|
60
getdependencies.sh
Executable file
60
getdependencies.sh
Executable file
@ -0,0 +1,60 @@
|
||||
#!/bin/bash
|
||||
|
||||
shopt -s nullglob dotglob
|
||||
directory=(dependencies/*)
|
||||
if [ ${#directory[@]} -gt 0 ]; then
|
||||
read -p "Found Dependency Directory. Did you want to wipe? (y/n) " -n 1 -r
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
rm -R dependencies
|
||||
echo
|
||||
read -p "Did you want to resync? (y/n) " -n 1 -r
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
echo
|
||||
echo "resyncing"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
echo
|
||||
echo "starting resync"
|
||||
else
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
echo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
apt-get -y install git
|
||||
|
||||
mkdir dependencies
|
||||
cd dependencies
|
||||
|
||||
git clone https://github.com/yorkane/socks-nginx-module.git
|
||||
git clone https://github.com/nbs-system/naxsi.git
|
||||
git clone https://github.com/openresty/headers-more-nginx-module.git
|
||||
git clone https://github.com/openresty/echo-nginx-module.git
|
||||
|
||||
#some required stuff for lua/luajit. obviously versions should be ckecked with every install/update
|
||||
git clone https://github.com/openresty/lua-nginx-module
|
||||
cd lua-nginx-module
|
||||
git checkout v0.10.16
|
||||
cd ..
|
||||
git clone https://github.com/openresty/luajit2
|
||||
cd luajit2
|
||||
git checkout v2.1-20200102
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/vision5/ngx_devel_kit
|
||||
|
||||
git clone https://github.com/openresty/lua-resty-string
|
||||
|
||||
git clone https://github.com/cloudflare/lua-resty-cookie
|
||||
|
||||
git clone https://github.com/ittner/lua-gd/
|
||||
|
||||
git clone https://github.com/bungle/lua-resty-session
|
||||
|
||||
cd ..
|
204
lua/cap.lua
204
lua/cap.lua
@ -1,12 +1,13 @@
|
||||
-- encryption key and salt must be shared across fronts. salt must be 8 chars
|
||||
local key = "encryption_key"
|
||||
local salt = "salt1234"
|
||||
local salt = "1saltkey"
|
||||
-- for how long the captcha is valid. 120 sec is for testing, 3600 1 hour should be production.
|
||||
local session_timeout = 3600
|
||||
|
||||
aes = require "resty.aes"
|
||||
str = require "resty.string"
|
||||
cook = require "resty.cookie"
|
||||
random = require "resty.random"
|
||||
|
||||
aes_128_cbc_sha512x1 = aes:new(key, salt, aes.cipher(128,"cbc"), aes.hash.sha512, 1)
|
||||
|
||||
@ -88,74 +89,111 @@ if ngx.var.request_method == "POST" and ngx.var.http_referer == nil then
|
||||
ngx.exit(444)
|
||||
end
|
||||
|
||||
-- check if cookie is blacklisted by rate limiter. if it is show the client a message and exit. can get creative with this.
|
||||
local field, err = cookie:get("dcap")
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
local bct, btcflags = blocked_cookies:get(field)
|
||||
if bct then
|
||||
ngx.header.content_type = 'text/plain'
|
||||
ngx.say("403 DDOS fliter killed your path. (You probably sent too many requests at once). Not calling you a bot, bot, but grab a new identity and try again.")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
-- check cookie support similar to testcookie
|
||||
if ngx.var.request_method == "GET" then
|
||||
local args = ngx.req.get_uri_args()
|
||||
if args['tca'] == "1" then
|
||||
local field, err = cookie:get("dcap")
|
||||
if err or not field then
|
||||
ngx.exit(403)
|
||||
end
|
||||
-- if cookie cannot be decrypted most likely it has been messed with
|
||||
local cookdata = aes_128_cbc_sha512x1:decrypt(fromhex(field))
|
||||
if not cookdata then
|
||||
ngx.header.content_type = 'text/plain'
|
||||
ngx.say("403 DDOS fliter killed your path. (You probably sent too many requests at once). Not calling you a bot, bot, but grab a new identity and try again.")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
cooktest = split(cookdata, "|")[1]
|
||||
if cooktest ~= "cap_not_solved" and cooktest ~= "captcha_solved" then
|
||||
ngx.exit(403)
|
||||
end
|
||||
end
|
||||
|
||||
-- try to set cookie. max-age is irrelevant as it can be faked and check is done against cookie content anyway. should be set to a large value otherwise it will annoy users
|
||||
local field, err = cookie:get("dcap")
|
||||
if err then
|
||||
local tstamp = ngx.now()
|
||||
local plaintext = "cap_not_solved|" .. tstamp .. "|1"
|
||||
--local tstamp = ngx.now() + slidingscalefunction
|
||||
local tstamp = ngx.now() + 10
|
||||
local plaintext = "queue|" .. tstamp .. "|1|" .. random.token(random.number(10,20))
|
||||
local ciphertext = tohex(aes_128_cbc_sha512x1:encrypt(plaintext))
|
||||
local ok, err = cookie:set({
|
||||
key = "dcap", value = ciphertext, path = "/",
|
||||
domain = ngx.var.host, httponly = true,
|
||||
max_age = 21600,
|
||||
samesite = "Strict"
|
||||
max_age = session_timeout,
|
||||
samesite = "Lax"
|
||||
})
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, err)
|
||||
return
|
||||
end
|
||||
ngx.header.content_type = 'text/html'
|
||||
ngx.say("<head> \
|
||||
<meta http-equiv=\"refresh\" content=\"1\"> \
|
||||
</head><a href=\"/\">One moment...</p>")
|
||||
ngx.header.content_type = 'text/html'
|
||||
local file = io.open("/etc/nginx/queue.html")
|
||||
local queue, err = file:read("*a")
|
||||
file:close()
|
||||
ngx.say(queue)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
else
|
||||
plaintext = aes_128_cbc_sha512x1:decrypt(fromhex(field))
|
||||
if not plaintext then
|
||||
ngx.header.content_type = 'text/plain'
|
||||
ngx.say("403 DDOS fliter killed your path. (You probably sent too many requests at once). Not calling you a bot, bot, but grab a new identity and try again.")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
cookdata = split(plaintext,"|")
|
||||
local expired = nil
|
||||
if (cookdata[1] == "queue") then
|
||||
--if (tonumber(cookdata[2])) > ngx.now() or (tonumber(cookdata[2])) > tonumber(cookdata[2]) + slidingscalefunction then
|
||||
if (tonumber(cookdata[2])) > ngx.now() or (tonumber(cookdata[2])) > ngx.now() + 40 then
|
||||
if pa ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, ngx.var.remote_addr, ngx.var.proxy_protocol_addr)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to create timer: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
blocked_cookies:set(field, 1, 3600)
|
||||
ngx.exit(444)
|
||||
end
|
||||
|
||||
require "caphtml_d"
|
||||
|
||||
local expired = nil
|
||||
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
|
||||
elseif (cookdata[1] == "cap_not_solved") then
|
||||
if (tonumber(cookdata[2]) + 60) > ngx.now() then
|
||||
if pa ~= "no_proxy" then
|
||||
local ok, err = ngx.timer.at(0, kill_circuit, ngx.var.remote_addr, ngx.var.proxy_protocol_addr)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to create timer: ", err)
|
||||
return
|
||||
end
|
||||
end
|
||||
ngx.header.content_type = 'text/html'
|
||||
ngx.say("<h1>THINK OF WHAT YOU HAVE DONE!</h1>")
|
||||
ngx.say("<p>That captcha was generated just for you. And look at what you did. Ignoring the captcha... not even giving an incorrect answer to his meaningless existence. You couldn't even give him false hope. Shame on you.</p>")
|
||||
ngx.say("<p>Don't immedately refresh for a new captcha! Try and fail. You must now wait about a minute for a new captcha to load.</p>")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
-- captcha generator functions
|
||||
require "caphtml_d"
|
||||
|
||||
local expired = nil
|
||||
|
||||
if (tonumber(cookdata[2]) + session_timeout) < ngx.now() then
|
||||
expired = true
|
||||
caperror = "Session expired"
|
||||
end
|
||||
|
||||
if cookdata[1] ~= "captcha_solved" or expired then
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- captcha generator functions
|
||||
require "caphtml_d"
|
||||
|
||||
local field, err = cookie:get("dcap")
|
||||
if not field or field == nil then
|
||||
displaycap()
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
-- check if cookie is blacklisted by rate limiter. if it is show the client a message and exit. can get creative with this.
|
||||
local blocked_cookies = ngx.shared.blocked_cookies
|
||||
local bct, btcflags = blocked_cookies:get(field)
|
||||
if bct then
|
||||
ngx.log(ngx.ERR, "Cookie " .. field .. " blacklisted.")
|
||||
ngx.header.content_type = 'text/plain'
|
||||
ngx.say("403 DDOS fliter killed your path. (You probably sent too many requests at once). Not calling you a bot, bot, but grab a new identity and try again.")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
if ngx.var.request_method == "POST" then
|
||||
local field, err = cookie:get("dcap")
|
||||
if err then
|
||||
@ -172,24 +210,28 @@ if ngx.var.request_method == "POST" then
|
||||
end
|
||||
cookdata = split(plaintext,"|")
|
||||
local expired = nil
|
||||
if (tonumber(cookdata[2]) + session_timeout) < ngx.now() then
|
||||
expired = true
|
||||
caperror = "Session expired"
|
||||
displaycap()
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
if cookdata[1] == "captcha_solved" and not expired then
|
||||
if (cookdata[1] == "cap_not_solved") then
|
||||
if (tonumber(cookdata[2]) + session_timeout) < ngx.now() then
|
||||
expired = true
|
||||
require "caphtml_d"
|
||||
caperror = "Session expired"
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
elseif (cookdata[1] == "captcha_solved") then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
require "caphtml_d"
|
||||
|
||||
-- resty has a library for parsing POST data but it's not really needed
|
||||
ngx.req.read_body()
|
||||
local dataraw = ngx.req.get_body_data()
|
||||
if dataraw == nil then
|
||||
caperror = "You didn't submit anything. Try again."
|
||||
displaycap()
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
@ -213,24 +255,25 @@ if ngx.var.request_method == "POST" then
|
||||
|
||||
if (tonumber(cookdata[2]) + 60) < ngx.now() then
|
||||
caperror = "Captcha expired"
|
||||
displaycap()
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
if sentcap == cookdata[3] then
|
||||
if string.lower(sentcap) == string.lower(cookdata[3]) then
|
||||
local newcookdata = ""
|
||||
cookdata[1] = "captcha_solved"
|
||||
for k,v in pairs(cookdata) do
|
||||
newcookdata = newcookdata .. "|" .. v
|
||||
end
|
||||
newcookdata = newcookdata .. "|" .. random.token(random.number(10,20))
|
||||
local tstamp = ngx.now()
|
||||
local ciphertext = tohex(aes_128_cbc_sha512x1:encrypt(newcookdata))
|
||||
local ok, err = cookie:set({
|
||||
key = "dcap", value = ciphertext, path = "/",
|
||||
domain = ngx.var.host, httponly = true,
|
||||
max_age = 21600,
|
||||
samesite = "Strict"
|
||||
max_age = session_timeout,
|
||||
samesite = "Lax"
|
||||
})
|
||||
if not ok then
|
||||
ngx.say("cookie error")
|
||||
@ -244,39 +287,8 @@ if ngx.var.request_method == "POST" then
|
||||
else
|
||||
caperror = "You Got That Wrong. Try again"
|
||||
end
|
||||
|
||||
else
|
||||
caperror = "Session invalid or expired"
|
||||
displaycap()
|
||||
displaycap(session_timeout)
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
end
|
||||
|
||||
plaintext = aes_128_cbc_sha512x1:decrypt(fromhex(field))
|
||||
if not plaintext then
|
||||
ngx.header.content_type = 'text/plain'
|
||||
ngx.say("403 DDOS fliter killed your path. (You probably sent too many requests at once). Not calling you a bot, bot, but grab a new identity and try again.")
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
cookdata = split(plaintext,"|")
|
||||
|
||||
if not cookdata then
|
||||
displaycap()
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
local expired = nil
|
||||
if (tonumber(cookdata[2]) + session_timeout) < ngx.now() then
|
||||
expired = true
|
||||
caperror = "Session expired"
|
||||
end
|
||||
|
||||
if cookdata[1] ~= "captcha_solved" or expired then
|
||||
displaycap()
|
||||
ngx.flush()
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
|
||||
|
||||
##################################
|
||||
## INTERNAL RULES IDS:1-999 ##
|
||||
##################################
|
||||
@ -16,30 +18,30 @@
|
||||
##################################
|
||||
## SQL Injections IDs:1000-1099 ##
|
||||
##################################
|
||||
MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop" "msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;
|
||||
MainRule "str:\"" "msg:double quote" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8,$XSS:8" id:1001;
|
||||
MainRule "str:0x" "msg:0x, possible hex encoding" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;
|
||||
#MainRule "rx:select|union|update|delete|insert|table|from|ascii|hex|unhex|drop" "msg:sql keywords" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1000;
|
||||
#MainRule "str:\"" "msg:double quote" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8,$XSS:8" id:1001;
|
||||
MainRule "str:0x" "msg:0x, possible hex encoding" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:2" id:1002;
|
||||
## Hardcore rules
|
||||
MainRule "str:/*" "msg:mysql comment (/*)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1003;
|
||||
MainRule "str:*/" "msg:mysql comment (*/)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1004;
|
||||
MainRule "str:|" "msg:mysql keyword (|)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1005;
|
||||
MainRule "str:&&" "msg:mysql keyword (&&)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1006;
|
||||
MainRule "str:/*" "msg:mysql comment (/*)" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1003;
|
||||
MainRule "str:*/" "msg:mysql comment (*/)" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1004;
|
||||
MainRule "str:|" "msg:mysql keyword (|)" "mz:URL|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1005;
|
||||
MainRule "str:&&" "msg:mysql keyword (&&)" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:8" id:1006;
|
||||
## end of hardcore rules
|
||||
MainRule "str:--" "msg:mysql comment (--)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1007;
|
||||
MainRule "str:;" "msg:semicolon" "mz:BODY|URL|ARGS" "s:$SQL:4,$XSS:8" id:1008;
|
||||
MainRule "str:=" "msg:equal sign in var, probable sql/xss" "mz:ARGS|BODY" "s:$SQL:2" id:1009;
|
||||
MainRule "str:(" "msg:open parenthesis, probable sql/xss" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1010;
|
||||
MainRule "str:)" "msg:close parenthesis, probable sql/xss" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1011;
|
||||
MainRule "str:'" "msg:simple quote" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1013;
|
||||
MainRule "str:," "msg:comma" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1015;
|
||||
MainRule "str:#" "msg:mysql comment (#)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1016;
|
||||
MainRule "str:@@" "msg:double arobase (@@)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1017;
|
||||
MainRule "str:--" "msg:mysql comment (--)" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1007;
|
||||
#MainRule "str:;" "msg:; in stuff" "mz:BODY|URL|ARGS" "s:$SQL:4,$XSS:8" id:1008;
|
||||
#MainRule "str:=" "msg:equal in var, probable sql/xss" "mz:ARGS|BODY" "s:$SQL:2" id:1009;
|
||||
MainRule "str:(" "msg:parenthesis, probable sql/xss" "mz:URL|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1010;
|
||||
MainRule "str:)" "msg:parenthesis, probable sql/xss" "mz:URL|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1011;
|
||||
MainRule "str:'" "msg:simple quote" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$SQL:4,$XSS:8" id:1013;
|
||||
#MainRule "str:," "msg:, in stuff" "mz:URL|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1015;
|
||||
#MainRule "str:#" "msg:mysql comment (#)" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1016;
|
||||
MainRule "str:@@" "msg:double @@" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$SQL:4" id:1017;
|
||||
|
||||
###############################
|
||||
## OBVIOUS RFI IDs:1100-1199 ##
|
||||
###############################
|
||||
MainRule "str:http://" "msg:http:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1100;
|
||||
MainRule "str:https://" "msg:https:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1101;
|
||||
#MainRule "str:http://" "msg:http:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1100;
|
||||
#MainRule "str:https://" "msg:https:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1101;
|
||||
MainRule "str:ftp://" "msg:ftp:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1102;
|
||||
MainRule "str:php://" "msg:php:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1103;
|
||||
MainRule "str:sftp://" "msg:sftp:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1104;
|
||||
@ -48,41 +50,37 @@ MainRule "str:data://" "msg:data:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "
|
||||
MainRule "str:glob://" "msg:glob:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1107;
|
||||
MainRule "str:phar://" "msg:phar:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1108;
|
||||
MainRule "str:file://" "msg:file:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1109;
|
||||
MainRule "str:gopher://" "msg:gopher:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1110;
|
||||
MainRule "str:gopher://" "msg:file:// scheme" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$RFI:8" id:1110;
|
||||
|
||||
#######################################
|
||||
## Directory traversal IDs:1200-1299 ##
|
||||
#######################################
|
||||
MainRule "str:.." "msg:double dot" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1200;
|
||||
MainRule "str:.." "msg:double dot" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1200;
|
||||
MainRule "str:/etc/passwd" "msg:obvious probe" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1202;
|
||||
MainRule "str:c:\\" "msg:obvious windows path" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1203;
|
||||
MainRule "str:cmd.exe" "msg:obvious probe" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1204;
|
||||
MainRule "str:\\" "msg:backslash" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1205;
|
||||
MainRule "str:\\" "msg:backslash" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:4" id:1205;
|
||||
#MainRule "str:/" "msg:slash in args" "mz:ARGS|BODY|$HEADERS_VAR:Cookie" "s:$TRAVERSAL:2" id:1206;
|
||||
|
||||
########################################
|
||||
## Cross Site Scripting IDs:1300-1399 ##
|
||||
########################################
|
||||
MainRule "str:<" "msg:html open tag" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1302;
|
||||
MainRule "str:>" "msg:html close tag" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1303;
|
||||
MainRule "str:[" "msg:open square backet ([), possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1310;
|
||||
MainRule "str:]" "msg:close square bracket (]), possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1311;
|
||||
MainRule "str:~" "msg:tilde (~) character" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1312;
|
||||
MainRule "str:`" "msg:grave accent (`)" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1314;
|
||||
MainRule "rx:%[2|3]." "msg:double encoding" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1315;
|
||||
MainRule "str:<" "msg:html open tag" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1302;
|
||||
MainRule "str:>" "msg:html close tag" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1303;
|
||||
#MainRule "str:[" "msg:[, possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1310;
|
||||
#MainRule "str:]" "msg:], possible js" "mz:BODY|URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1311;
|
||||
MainRule "str:~" "msg:~ character" "mz:URL|ARGS|$HEADERS_VAR:Cookie" "s:$XSS:4" id:1312;
|
||||
MainRule "str:`" "msg:grave accent !" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1314;
|
||||
#MainRule "rx:%[2|3]." "msg:double encoding !" "mz:ARGS|URL|BODY|$HEADERS_VAR:Cookie" "s:$XSS:8" id:1315;
|
||||
|
||||
####################################
|
||||
## Evading tricks IDs: 1400-1500 ##
|
||||
####################################
|
||||
MainRule "str:&#" "msg:utf7/8 encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1400;
|
||||
MainRule "str:%U" "msg:M$ encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1401;
|
||||
MainRule "str:&#" "msg: utf7/8 encoding" "mz:ARGS|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1400;
|
||||
MainRule "str:%U" "msg: M$ encoding" "mz:ARGS|BODY|URL|$HEADERS_VAR:Cookie" "s:$EVADE:4" id:1401;
|
||||
|
||||
#############################
|
||||
## File uploads: 1500-1600 ##
|
||||
#############################
|
||||
MainRule "rx:\.ph|\.asp|\.ht" "msg:asp/php file upload" "mz:FILE_EXT" "s:$UPLOAD:8" id:1500;
|
||||
MainRule "rx:\.ph|\.asp|\.ht*" "msg:asp/php file upload!" "mz:FILE_EXT" "s:$UPLOAD:8" id:1500;
|
||||
|
||||
MainRule "str:/public/uploads/" "msg:Access to uploads" "mz:URL" "s:$UWA:8" id:42000400;
|
||||
MainRule "str:/public/image/" "msg:Access to image folder" "mz:URL" "s:$UWA:8" id:42000401;
|
||||
MainRule "str:/public/" "msg:Access to public folder" "mz:URL" "s:$UWA:8" id:42000402;
|
||||
MainRule "str:/system/" "msg:Access to system folder" "mz:URL" "s:$UWA:8" id:42000403;
|
@ -2,3 +2,6 @@ BasicRule wl:10;
|
||||
BasicRule wl:20;
|
||||
BasicRule wl:16;
|
||||
BasicRule wl:12;
|
||||
BasicRule wl:13;
|
||||
BasicRule wl:1310;
|
||||
BasicRule wl:1311;
|
@ -70,18 +70,14 @@ cd ..
|
||||
git clone https://github.com/bungle/lua-resty-session
|
||||
cp -a lua-resty-session/lib/resty/session* /usr/local/lib/lua/resty/
|
||||
|
||||
git clone https://github.com/ittner/lua-gd/
|
||||
cd lua-gd
|
||||
gcc -o gd.so -DGD_XPM -DGD_JPEG -DGD_FONTCONFIG -DGD_FREETYPE -DGD_PNG -DGD_GIF -O2 -Wall -fPIC -fomit-frame-pointer -I/usr/local/include/luajit-2.1 -DVERSION=\"2.0.33r3\" -shared -lgd luagd.c
|
||||
mv gd.so /usr/local/lib/lua/5.1/gd.so
|
||||
cd ..
|
||||
|
||||
wget -O /usr/local/lib/lua/resty/aes_functions.lua https://github.com/c64bob/lua-resty-aes/raw/master/lib/resty/aes_functions.lua
|
||||
|
||||
#include seems to be a bit mssed up with luajit
|
||||
mkdir /etc/nginx/resty
|
||||
ln -s /usr/local/lib/lua/resty/ /etc/nginx/resty/
|
||||
|
||||
wget -O /usr/local/lib/lua/resty/random.lua https://raw.githubusercontent.com/bungle/lua-resty-random/master/lib/resty/random.lua
|
||||
|
||||
make -j16 modules
|
||||
|
||||
cp -r objs modules
|
||||
|
21
nginx.conf
21
nginx.conf
@ -2,6 +2,7 @@ user www-data;
|
||||
worker_processes auto;
|
||||
worker_priority -5;
|
||||
worker_rlimit_nofile 1024000;
|
||||
timer_resolution 10000ms;
|
||||
pid /run/nginx.pid;
|
||||
load_module modules/modules/ngx_http_headers_more_filter_module.so;
|
||||
load_module modules/modules/ngx_http_naxsi_module.so;
|
||||
@ -11,7 +12,9 @@ load_module modules/modules/ndk_http_module.so;
|
||||
load_module modules/modules/ngx_http_lua_module.so;
|
||||
|
||||
events {
|
||||
worker_connections 4096;
|
||||
worker_connections 8096;
|
||||
use epoll;
|
||||
multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
@ -28,18 +31,19 @@ http {
|
||||
|
||||
reset_timedout_connection on;
|
||||
|
||||
lua_shared_dict blocked_cookies 100M;
|
||||
lua_shared_dict blocked_cookies 100M;
|
||||
|
||||
# Timeouts
|
||||
client_body_timeout 10s;
|
||||
client_header_timeout 10s;
|
||||
client_body_timeout 30s;
|
||||
client_header_timeout 30s;
|
||||
keepalive_timeout 240s;
|
||||
keepalive_requests 200000;
|
||||
send_timeout 120s;
|
||||
client_max_body_size 10m;
|
||||
client_body_buffer_size 10m;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 30s;
|
||||
proxy_read_timeout 30s;
|
||||
proxy_connect_timeout 120s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_read_timeout 120s;
|
||||
|
||||
log_format detailed escape=json
|
||||
'{'
|
||||
@ -57,7 +61,6 @@ http {
|
||||
'"http_user_agent": "$http_user_agent"'
|
||||
'}';
|
||||
#access_log /var/log/site.access.log detailed;
|
||||
|
||||
proxy_redirect off;
|
||||
|
||||
# Gzipping Content
|
||||
@ -75,7 +78,7 @@ http {
|
||||
include /etc/nginx/naxsi_core.rules;
|
||||
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-Frame-Options "DENY";
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Xss-Protection "1; mode=block";
|
||||
|
||||
##
|
||||
|
1
queue.html
Normal file
1
queue.html
Normal file
File diff suppressed because one or more lines are too long
86
random.lua
Normal file
86
random.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local require = require
|
||||
local ffi = require "ffi"
|
||||
local ffi_cdef = ffi.cdef
|
||||
local ffi_new = ffi.new
|
||||
local ffi_str = ffi.string
|
||||
local ffi_typeof = ffi.typeof
|
||||
local C = ffi.C
|
||||
local type = type
|
||||
local random = math.random
|
||||
local randomseed = math.randomseed
|
||||
local concat = table.concat
|
||||
local tostring = tostring
|
||||
local pcall = pcall
|
||||
|
||||
ffi_cdef[[
|
||||
typedef unsigned char u_char;
|
||||
u_char * ngx_hex_dump(u_char *dst, const u_char *src, size_t len);
|
||||
int RAND_bytes(u_char *buf, int num);
|
||||
]]
|
||||
|
||||
local ok, new_tab = pcall(require, "table.new")
|
||||
if not ok then
|
||||
new_tab = function () return {} end
|
||||
end
|
||||
|
||||
local alnum = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M',
|
||||
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m',
|
||||
'n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'0','1','2','3','4','5','6','7','8','9'
|
||||
}
|
||||
|
||||
local t = ffi_typeof "uint8_t[?]"
|
||||
|
||||
local function bytes(len, format)
|
||||
local s = ffi_new(t, len)
|
||||
C.RAND_bytes(s, len)
|
||||
if not s then return nil end
|
||||
if format == "hex" then
|
||||
local b = ffi_new(t, len * 2)
|
||||
C.ngx_hex_dump(b, s, len)
|
||||
return ffi_str(b, len * 2), true
|
||||
else
|
||||
return ffi_str(s, len), true
|
||||
end
|
||||
end
|
||||
|
||||
local function seed()
|
||||
local a,b,c,d = bytes(4):byte(1, 4)
|
||||
return randomseed(a * 0x1000000 + b * 0x10000 + c * 0x100 + d)
|
||||
end
|
||||
|
||||
local function number(min, max, reseed)
|
||||
if reseed then seed() end
|
||||
if min and max then return random(min, max)
|
||||
elseif min then return random(min)
|
||||
else return random() end
|
||||
end
|
||||
|
||||
local function token(len, chars, sep)
|
||||
chars = chars or alnum
|
||||
local count
|
||||
local token = new_tab(len, 0)
|
||||
if type(chars) ~= "table" then
|
||||
chars = tostring(chars)
|
||||
count = #chars
|
||||
local n
|
||||
for i=1,len do
|
||||
n = number(1, count)
|
||||
token[i] = chars:sub(n, n)
|
||||
end
|
||||
else
|
||||
count = #chars
|
||||
for i=1,len do token[i] = chars[number(1, count)] end
|
||||
end
|
||||
return concat(token, sep)
|
||||
end
|
||||
|
||||
seed()
|
||||
|
||||
return {
|
||||
bytes = bytes,
|
||||
number = number,
|
||||
token = token
|
||||
}
|
225
resty/aes_functions.lua
Normal file
225
resty/aes_functions.lua
Normal file
@ -0,0 +1,225 @@
|
||||
-- Copyright (C) by Yichun Zhang (agentzh)
|
||||
|
||||
|
||||
local ffi = require "ffi"
|
||||
local ffi_new = ffi.new
|
||||
local ffi_gc = ffi.gc
|
||||
local ffi_str = ffi.string
|
||||
local ffi_copy = ffi.copy
|
||||
local C = ffi.C
|
||||
local setmetatable = setmetatable
|
||||
local type = type
|
||||
|
||||
|
||||
local _M = { _VERSION = '0.12' }
|
||||
|
||||
local mt = { __index = _M }
|
||||
|
||||
|
||||
ffi.cdef[[
|
||||
typedef struct engine_st ENGINE;
|
||||
|
||||
typedef struct evp_cipher_st EVP_CIPHER;
|
||||
typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
|
||||
|
||||
typedef struct env_md_ctx_st EVP_MD_CTX;
|
||||
typedef struct env_md_st EVP_MD;
|
||||
|
||||
const EVP_MD *EVP_md5(void);
|
||||
const EVP_MD *EVP_sha(void);
|
||||
const EVP_MD *EVP_sha1(void);
|
||||
const EVP_MD *EVP_sha224(void);
|
||||
const EVP_MD *EVP_sha256(void);
|
||||
const EVP_MD *EVP_sha384(void);
|
||||
const EVP_MD *EVP_sha512(void);
|
||||
|
||||
const EVP_CIPHER *EVP_aes_128_ecb(void);
|
||||
const EVP_CIPHER *EVP_aes_128_cbc(void);
|
||||
const EVP_CIPHER *EVP_aes_128_cfb1(void);
|
||||
const EVP_CIPHER *EVP_aes_128_cfb8(void);
|
||||
const EVP_CIPHER *EVP_aes_128_cfb128(void);
|
||||
const EVP_CIPHER *EVP_aes_128_ofb(void);
|
||||
const EVP_CIPHER *EVP_aes_128_ctr(void);
|
||||
const EVP_CIPHER *EVP_aes_192_ecb(void);
|
||||
const EVP_CIPHER *EVP_aes_192_cbc(void);
|
||||
const EVP_CIPHER *EVP_aes_192_cfb1(void);
|
||||
const EVP_CIPHER *EVP_aes_192_cfb8(void);
|
||||
const EVP_CIPHER *EVP_aes_192_cfb128(void);
|
||||
const EVP_CIPHER *EVP_aes_192_ofb(void);
|
||||
const EVP_CIPHER *EVP_aes_192_ctr(void);
|
||||
const EVP_CIPHER *EVP_aes_256_ecb(void);
|
||||
const EVP_CIPHER *EVP_aes_256_cbc(void);
|
||||
const EVP_CIPHER *EVP_aes_256_cfb1(void);
|
||||
const EVP_CIPHER *EVP_aes_256_cfb8(void);
|
||||
const EVP_CIPHER *EVP_aes_256_cfb128(void);
|
||||
const EVP_CIPHER *EVP_aes_256_ofb(void);
|
||||
const EVP_CIPHER *EVP_aes_256_ctr(void);
|
||||
|
||||
EVP_CIPHER_CTX *EVP_CIPHER_CTX_new();
|
||||
void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a);
|
||||
|
||||
int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
|
||||
ENGINE *impl, unsigned char *key, const unsigned char *iv);
|
||||
|
||||
int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
|
||||
const unsigned char *in, int inl);
|
||||
|
||||
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
|
||||
|
||||
int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
|
||||
ENGINE *impl, unsigned char *key, const unsigned char *iv);
|
||||
|
||||
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
|
||||
const unsigned char *in, int inl);
|
||||
|
||||
int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
|
||||
|
||||
int EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,
|
||||
const unsigned char *salt, const unsigned char *data, int datal,
|
||||
int count, unsigned char *key,unsigned char *iv);
|
||||
]]
|
||||
|
||||
local hash
|
||||
hash = {
|
||||
md5 = C.EVP_md5(),
|
||||
sha1 = C.EVP_sha1(),
|
||||
sha224 = C.EVP_sha224(),
|
||||
sha256 = C.EVP_sha256(),
|
||||
sha384 = C.EVP_sha384(),
|
||||
sha512 = C.EVP_sha512()
|
||||
}
|
||||
_M.hash = hash
|
||||
|
||||
local cipher
|
||||
cipher = function (size, _cipher)
|
||||
local _size = size or 128
|
||||
local _cipher = _cipher or "cbc"
|
||||
local func = "EVP_aes_" .. _size .. "_" .. _cipher
|
||||
if C[func] then
|
||||
return { size=_size, cipher=_cipher, method=C[func]()}
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
_M.cipher = cipher
|
||||
|
||||
function _M.new(self, key, salt, _cipher, _hash, hash_rounds)
|
||||
local encrypt_ctx = C.EVP_CIPHER_CTX_new()
|
||||
if encrypt_ctx == nil then
|
||||
return nil, "no memory"
|
||||
end
|
||||
|
||||
ffi_gc(encrypt_ctx, C.EVP_CIPHER_CTX_free)
|
||||
|
||||
local decrypt_ctx = C.EVP_CIPHER_CTX_new()
|
||||
if decrypt_ctx == nil then
|
||||
return nil, "no memory"
|
||||
end
|
||||
|
||||
ffi_gc(decrypt_ctx, C.EVP_CIPHER_CTX_free)
|
||||
|
||||
local _cipher = _cipher or cipher()
|
||||
local _hash = _hash or hash.md5
|
||||
local hash_rounds = hash_rounds or 1
|
||||
local _cipherLength = _cipher.size/8
|
||||
local gen_key = ffi_new("unsigned char[?]",_cipherLength)
|
||||
local gen_iv = ffi_new("unsigned char[?]",_cipherLength)
|
||||
|
||||
if type(_hash) == "table" then
|
||||
if not _hash.iv or #_hash.iv ~= 16 then
|
||||
return nil, "bad iv"
|
||||
end
|
||||
|
||||
if _hash.method then
|
||||
local tmp_key = _hash.method(key)
|
||||
|
||||
if #tmp_key ~= _cipherLength then
|
||||
return nil, "bad key length"
|
||||
end
|
||||
|
||||
ffi_copy(gen_key, tmp_key, _cipherLength)
|
||||
|
||||
elseif #key ~= _cipherLength then
|
||||
return nil, "bad key length"
|
||||
|
||||
else
|
||||
ffi_copy(gen_key, key, _cipherLength)
|
||||
end
|
||||
|
||||
ffi_copy(gen_iv, _hash.iv, 16)
|
||||
|
||||
else
|
||||
if salt and #salt ~= 8 then
|
||||
return nil, "salt must be 8 characters or nil"
|
||||
end
|
||||
|
||||
if C.EVP_BytesToKey(_cipher.method, _hash, salt, key, #key,
|
||||
hash_rounds, gen_key, gen_iv)
|
||||
~= _cipherLength
|
||||
then
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
if C.EVP_EncryptInit_ex(encrypt_ctx, _cipher.method, nil,
|
||||
gen_key, gen_iv) == 0 or
|
||||
C.EVP_DecryptInit_ex(decrypt_ctx, _cipher.method, nil,
|
||||
gen_key, gen_iv) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return setmetatable({
|
||||
_encrypt_ctx = encrypt_ctx,
|
||||
_decrypt_ctx = decrypt_ctx
|
||||
}, mt)
|
||||
end
|
||||
|
||||
|
||||
function _M.encrypt(self, s)
|
||||
local s_len = #s
|
||||
local max_len = s_len + 16
|
||||
local buf = ffi_new("unsigned char[?]", max_len)
|
||||
local out_len = ffi_new("int[1]")
|
||||
local tmp_len = ffi_new("int[1]")
|
||||
local ctx = self._encrypt_ctx
|
||||
|
||||
if C.EVP_EncryptInit_ex(ctx, nil, nil, nil, nil) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if C.EVP_EncryptUpdate(ctx, buf, out_len, s, s_len) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if C.EVP_EncryptFinal_ex(ctx, buf + out_len[0], tmp_len) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return ffi_str(buf, out_len[0] + tmp_len[0])
|
||||
end
|
||||
|
||||
|
||||
function _M.decrypt(self, s)
|
||||
local s_len = #s
|
||||
local buf = ffi_new("unsigned char[?]", s_len)
|
||||
local out_len = ffi_new("int[1]")
|
||||
local tmp_len = ffi_new("int[1]")
|
||||
local ctx = self._decrypt_ctx
|
||||
|
||||
if C.EVP_DecryptInit_ex(ctx, nil, nil, nil, nil) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if C.EVP_DecryptUpdate(ctx, buf, out_len, s, s_len) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
if C.EVP_DecryptFinal_ex(ctx, buf + out_len[0], tmp_len) == 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return ffi_str(buf, out_len[0] + tmp_len[0])
|
||||
end
|
||||
|
||||
|
||||
return _M
|
@ -1,6 +1,6 @@
|
||||
local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||
|
||||
function base64_encode(data)
|
||||
local function base64_encode(data)
|
||||
return ((data:gsub('.', function(x)
|
||||
local r,b='',x:byte()
|
||||
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
|
||||
@ -13,7 +13,7 @@ function base64_encode(data)
|
||||
end)..({ '', '==', '=' })[#data%3+1])
|
||||
end
|
||||
|
||||
function base64_decode(data)
|
||||
local function base64_decode(data)
|
||||
data = string.gsub(data, '[^'..b..'=]', '')
|
||||
return (data:gsub('.', function(x)
|
||||
if (x == '=') then return '' end
|
||||
@ -28,40 +28,105 @@ function base64_decode(data)
|
||||
end))
|
||||
end
|
||||
|
||||
function in_array(tab, val)
|
||||
for index, value in ipairs(tab) do
|
||||
if value == val then
|
||||
return true
|
||||
end
|
||||
function displaycap()
|
||||
|
||||
hour = random.number(0,11)
|
||||
minute = random.number(0,59)
|
||||
shour = tostring(hour)
|
||||
sminute = tostring(minute)
|
||||
if string.len(shour) < 2 then shour = "0" .. shour end
|
||||
if string.len(sminute) < 2 then sminute = "0" .. sminute end
|
||||
|
||||
local gd = require("gd")
|
||||
|
||||
local pickedtime = shour .. ":" .. sminute
|
||||
local radios = {}
|
||||
local ctimeindex = random.number(1,10)
|
||||
radios[ctimeindex] = {}
|
||||
radios[ctimeindex][1] = pickedtime
|
||||
radios[ctimeindex][2] = shour .. sminute
|
||||
for i = 1,ctimeindex-1,1 do
|
||||
fshour = tostring(random.number(0,11))
|
||||
fsminute = tostring(random.number(0,59))
|
||||
if string.len(fshour) < 2 then fshour = "0" .. fshour end
|
||||
if string.len(fsminute) < 2 then fsminute = "0" .. fsminute end
|
||||
local fpickedtime = fshour .. ":" .. fsminute
|
||||
radios[i] = {}
|
||||
radios[i][1] = fpickedtime
|
||||
radios[i][2] = fshour .. fsminute
|
||||
end
|
||||
for i = ctimeindex+1,10,1 do
|
||||
fshour = tostring(random.number(0,11))
|
||||
fsminute = tostring(random.number(0,59))
|
||||
if string.len(fshour) < 2 then fshour = "0" .. fshour end
|
||||
if string.len(fsminute) < 2 then fsminute = "0" .. fsminute end
|
||||
local fpickedtime = fshour .. ":" .. fsminute
|
||||
radios[i] = {}
|
||||
radios[i][1] = fpickedtime
|
||||
radios[i][2] = fshour .. fsminute
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function createClock(size, hours, minutes)
|
||||
local im = gd.createTrueColor(size, size)
|
||||
|
||||
local white = im:colorAllocate(random.number(200,255), random.number(200,255), random.number(200,255))
|
||||
local gray = im:colorAllocate(random.number(100,150), random.number(100,150), random.number(100,150))
|
||||
local black = im:colorAllocate(random.number(0,10), random.number(0,10), random.number(0,10))
|
||||
|
||||
local hrhand = im:colorAllocate(random.number(0,350), random.number(0,150), random.number(0,148))
|
||||
local minhand = im:colorAllocate(random.number(0,350), random.number(0,150), random.number(0,148))
|
||||
|
||||
local cxy = size/2
|
||||
|
||||
im:filledRectangle(0, 0, size, size, white)
|
||||
im:setThickness(2)
|
||||
im:arc(cxy, cxy, size, size, 0, 360, black)
|
||||
|
||||
local ang = 0
|
||||
local rang, gsize
|
||||
while ang < 360 do
|
||||
rang = math.rad(ang)
|
||||
if (ang % 90) == 0 then
|
||||
gsize = 0.75
|
||||
elseif (ang % 5) == 0 then
|
||||
gsize = 0.85
|
||||
else
|
||||
gsize = 0.90
|
||||
end
|
||||
im:line(
|
||||
cxy + gsize * cxy * math.sin(rang),
|
||||
size - (cxy + gsize * cxy * math.cos(rang)),
|
||||
cxy + cxy * 0.9 * math.sin(rang),
|
||||
size - (cxy + cxy * 0.9 * math.cos(rang)),
|
||||
gray)
|
||||
ang = ang + 6
|
||||
end
|
||||
|
||||
im:setThickness(math.max(1, size/50))
|
||||
im:line(cxy, cxy,
|
||||
cxy + 0.45 * size * math.sin(math.rad(6*minutes)),
|
||||
size - (cxy + 0.45 * size * math.cos(math.rad(6*minutes))),
|
||||
hrhand)
|
||||
|
||||
im:setThickness(math.max(1, size/25))
|
||||
rang = math.rad(30*hours + minutes/2)
|
||||
im:line(cxy, cxy,
|
||||
cxy + 0.25 * size * math.sin(rang),
|
||||
size - (cxy + 0.25 * size * math.cos(rang)),
|
||||
minhand)
|
||||
|
||||
im:setThickness(1)
|
||||
local sp = math.max(1, size/20)
|
||||
im:filledArc(cxy, cxy, sp, sp, 0, 360, black, gd.ARC)
|
||||
return im
|
||||
end
|
||||
|
||||
local gd = require("gd")
|
||||
local im = createClock(190, hour, minute)
|
||||
local imageraw = im:jpegStr(90)
|
||||
local imageb64 = base64_encode(imageraw)
|
||||
|
||||
function displaycap()
|
||||
math.randomseed(ngx.now())
|
||||
|
||||
local img_width = 150;
|
||||
local img_height = 150;
|
||||
|
||||
local capgrid = {}
|
||||
|
||||
local checkmin = 1
|
||||
local checkmax = 6
|
||||
local checktotal = 0
|
||||
|
||||
local sessiondice = "";
|
||||
|
||||
while checktotal < checkmin do
|
||||
for i=1,9,1 do
|
||||
check = math.random(0,1)
|
||||
if checktotal < checkmax and check == 1 then capgrid[i] = check else capgrid[i] = 0 end
|
||||
if check == 1 then
|
||||
checktotal = checktotal + 1
|
||||
sessiondice = sessiondice .. tostring(i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
@ -71,71 +136,26 @@ function displaycap()
|
||||
end
|
||||
|
||||
local tstamp = ngx.now()
|
||||
local newcookdata = "cap_not_solved|" .. tstamp .. "|"
|
||||
newcookdata = newcookdata .. sessiondice
|
||||
local newcookdata = "cap_not_solved|" .. tstamp .. "|" .. shour .. sminute
|
||||
|
||||
newcookdata = newcookdata .. "|" .. random.token(random.number(10,20))
|
||||
|
||||
local ciphertext = tohex(aes_128_cbc_sha512x1:encrypt(newcookdata))
|
||||
local ok, err = cookie:set({
|
||||
key = "dcap", value = ciphertext, path = "/",
|
||||
domain = ngx.var.host, httponly = true,
|
||||
max_age = 21600,
|
||||
samesite = "Strict"
|
||||
samesite = "Lax"
|
||||
})
|
||||
if not ok then
|
||||
ngx.say("cookie error")
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
local symbols_zero = {'○','□','♘','♢','▽','△','♖','✧','♔','♘','♕','♗','♙','♧'};
|
||||
local symbols_one = {'●','■','♞','♦','▼','▲','♜','✦','♚','♞','♛','♝','♟','♣'};
|
||||
|
||||
|
||||
local img = gd.createFromJpeg("/tmp/background-" .. math.random(0,25) .. ".jpg")
|
||||
|
||||
if img == nil then
|
||||
img = gd.createTrueColor(150, 150)
|
||||
local white = img:colorAllocate(255, 255, 255)
|
||||
img:filledRectangle(0, 0, img_width, img_height, white)
|
||||
end
|
||||
|
||||
img:setThickness(1)
|
||||
|
||||
-- if 0 each row will be horizontal
|
||||
local draw_angle = 0
|
||||
|
||||
local current_row = 1
|
||||
local capstring = ""
|
||||
for i=1,9,1 do
|
||||
local symbol_id = math.random(1,14)
|
||||
local fillcolor = img:colorAllocate(math.random(5,255), math.random(5,255), math.random(5,255))
|
||||
if capgrid[i] == 1 then
|
||||
capstring = capstring .. symbols_one[symbol_id]
|
||||
else
|
||||
capstring = capstring .. symbols_zero[symbol_id]
|
||||
end
|
||||
capstring = capstring .. " "
|
||||
if i % 3 == 0 then
|
||||
if draw_angle == 1 then
|
||||
angle = math.rad(math.random(0,10))
|
||||
else
|
||||
angle = 0
|
||||
end
|
||||
if current_row == 1 then
|
||||
img:stringFT(fillcolor, "/etc/nginx/font.ttf", math.random(18,22), angle, math.random(10,50), math.random(30,60), capstring)
|
||||
elseif current_row == 2 then
|
||||
img:stringFT(fillcolor, "/etc/nginx/font.ttf", math.random(18,22), angle, math.random(10,50), math.random(60,90), capstring)
|
||||
else
|
||||
img:stringFT(fillcolor, "/etc/nginx/font.ttf", math.random(18,22), angle, math.random(10,50), math.random(100,130), capstring)
|
||||
end
|
||||
current_row = current_row + 1
|
||||
capstring = ""
|
||||
end
|
||||
end
|
||||
imgbase64 = base64_encode(img:pngStrEx(6))
|
||||
|
||||
|
||||
ngx.header.content_type = 'text/html';
|
||||
ngx.say("<html lang=en> \
|
||||
ngx.say("<!DOCTYPE html> \
|
||||
<html lang=en> \
|
||||
<head> \
|
||||
<title>DDOS Protection</title> \
|
||||
<meta charset=\"UTF-8\"> \
|
||||
@ -166,34 +186,95 @@ if caperror ~= nil
|
||||
then
|
||||
ngx.say("<p class=\"alert alert-danger text-center\"><strong>Error: </strong>" .. caperror .. "</p>")
|
||||
else
|
||||
ngx.say("<p>Due to on-going DDOS attacks against our servers, you must complete a captcha challenge to prove you are human.</p>")
|
||||
ngx.say("<p>Prove that you are human. Select the time shown on the clock image.</p>")
|
||||
end
|
||||
|
||||
ngx.say("<form class=\"ddos_form\" method=\"post\"> \
|
||||
<div class=\"captchav2\" style=\"margin-bottom:15px;\"> \
|
||||
<div class=\"imgWrap\" style=\"border:1px solid #000;background-image:url(data:image/png;base64," .. imgbase64 .. "\"></div>")
|
||||
ngx.say("<div class=\"inputWrap\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"1\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"2\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"3\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"4\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"5\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"6\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"7\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"8\"> \
|
||||
<input type=\"checkbox\" name=\"cap\" value=\"9\">")
|
||||
ngx.say("<div class=\"c1\"></div> \
|
||||
<div class=\"c2\"></div> \
|
||||
<div class=\"c3\"></div> \
|
||||
<div class=\"c4\"></div> \
|
||||
<div class=\"c5\"></div> \
|
||||
<div class=\"c6\"></div> \
|
||||
<div class=\"c7\"></div> \
|
||||
<div class=\"c8\"></div> \
|
||||
<div class=\"c9\"></div>")
|
||||
ngx.say("</div> \
|
||||
</div> \
|
||||
<button type=\"submit\">Verify</button> \
|
||||
<div class=\"imgWrap\" style=\"border:2px solid #fff; max-width: 100%; border-radius: 50%; background-image:url(data:image/png;base64," .. imageb64 .. "\"></div>")
|
||||
ngx.say("</div>");
|
||||
ngx.say("<div style=\"margin-bottom: 15px;\">")
|
||||
ngx.say("<select class=\"center\" name=\"cap\" required>")
|
||||
for i = 0,11,1 do
|
||||
if i < 10 then si = "0" .. tostring(i) else si = i end
|
||||
ngx.say("<option value=\"" .. si .. "\">" .. si .. "</option>\n")
|
||||
end
|
||||
ngx.say("</select> : ")
|
||||
ngx.say("<select name=\"cap\" required>")
|
||||
for i = 0,59,1 do
|
||||
if i < 10 then si = "0" .. tostring(i) else si = i end
|
||||
ngx.say("<option value=\"" .. si .. "\">" .. si .. "</option>\n")
|
||||
end
|
||||
ngx.say("</select>")
|
||||
--ngx.say("<input type=\"text\" required name=\"cap\" maxlength=\"2\" size=\"2\" placeholder=\"hh\"> : ")
|
||||
--ngx.say("<input type=\"text\" required name=\"cap\" maxlength=\"2\" size=\"2\" placeholder=\"mm\">")
|
||||
ngx.say("</div>");
|
||||
ngx.say("<div class=\"expire\"> \
|
||||
<div class=\"timer\"> \
|
||||
<div class=\"time-part-wrapper\"> \
|
||||
<div class=\"time-part seconds tens\"> \
|
||||
<div class=\"digit-wrapper\"> \
|
||||
<span class=\"digit\">0</span> \
|
||||
<span class=\"digit\">5</span> \
|
||||
<span class=\"digit\">4</span> \
|
||||
<span class=\"digit\">3</span> \
|
||||
<span class=\"digit\">2</span> \
|
||||
<span class=\"digit\">1</span> \
|
||||
<span class=\"digit\">0</span> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class=\"time-part seconds ones\"> \
|
||||
<div class=\"digit-wrapper\"> \
|
||||
<span class=\"digit\">0</span> \
|
||||
<span class=\"digit\">9</span> \
|
||||
<span class=\"digit\">8</span> \
|
||||
<span class=\"digit\">7</span> \
|
||||
<span class=\"digit\">6</span> \
|
||||
<span class=\"digit\">5</span> \
|
||||
<span class=\"digit\">4</span> \
|
||||
<span class=\"digit\">3</span> \
|
||||
<span class=\"digit\">2</span> \
|
||||
<span class=\"digit\">1</span> \
|
||||
<span class=\"digit\">0</span> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class=\"time-part-wrapper\"> \
|
||||
<div class=\"time-part hundredths tens\"> \
|
||||
<div class=\"digit-wrapper\"> \
|
||||
<span class=\"digit\">0</span> \
|
||||
<span class=\"digit\">9</span> \
|
||||
<span class=\"digit\">8</span> \
|
||||
<span class=\"digit\">7</span> \
|
||||
<span class=\"digit\">6</span> \
|
||||
<span class=\"digit\">5</span> \
|
||||
<span class=\"digit\">4</span> \
|
||||
<span class=\"digit\">3</span> \
|
||||
<span class=\"digit\">2</span> \
|
||||
<span class=\"digit\">1</span> \
|
||||
<span class=\"digit\">0</span> \
|
||||
</div> \
|
||||
</div> \
|
||||
<div class=\"time-part hundredths ones\"> \
|
||||
<div class=\"digit-wrapper\"> \
|
||||
<span class=\"digit\">0</span> \
|
||||
<span class=\"digit\">9</span> \
|
||||
<span class=\"digit\">8</span> \
|
||||
<span class=\"digit\">7</span> \
|
||||
<span class=\"digit\">6</span> \
|
||||
<span class=\"digit\">5</span> \
|
||||
<span class=\"digit\">4</span> \
|
||||
<span class=\"digit\">3</span> \
|
||||
<span class=\"digit\">2</span> \
|
||||
<span class=\"digit\">1</span> \
|
||||
<span class=\"digit\">0</span> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div> \
|
||||
</div>")
|
||||
|
||||
ngx.say("<button class=\"before\" type=\"submit\">Verify</button> \
|
||||
<button class=\"expired\" type=\"submit\"> Refresh (expired)</button> \
|
||||
</form> \
|
||||
</div> \
|
||||
</div> \
|
||||
|
86
resty/core/random.lua
Normal file
86
resty/core/random.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local require = require
|
||||
local ffi = require "ffi"
|
||||
local ffi_cdef = ffi.cdef
|
||||
local ffi_new = ffi.new
|
||||
local ffi_str = ffi.string
|
||||
local ffi_typeof = ffi.typeof
|
||||
local C = ffi.C
|
||||
local type = type
|
||||
local random = math.random
|
||||
local randomseed = math.randomseed
|
||||
local concat = table.concat
|
||||
local tostring = tostring
|
||||
local pcall = pcall
|
||||
|
||||
ffi_cdef[[
|
||||
typedef unsigned char u_char;
|
||||
u_char * ngx_hex_dump(u_char *dst, const u_char *src, size_t len);
|
||||
int RAND_bytes(u_char *buf, int num);
|
||||
]]
|
||||
|
||||
local ok, new_tab = pcall(require, "table.new")
|
||||
if not ok then
|
||||
new_tab = function () return {} end
|
||||
end
|
||||
|
||||
local alnum = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M',
|
||||
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
|
||||
'a','b','c','d','e','f','g','h','i','j','k','l','m',
|
||||
'n','o','p','q','r','s','t','u','v','w','x','y','z',
|
||||
'0','1','2','3','4','5','6','7','8','9'
|
||||
}
|
||||
|
||||
local t = ffi_typeof "uint8_t[?]"
|
||||
|
||||
local function bytes(len, format)
|
||||
local s = ffi_new(t, len)
|
||||
C.RAND_bytes(s, len)
|
||||
if not s then return nil end
|
||||
if format == "hex" then
|
||||
local b = ffi_new(t, len * 2)
|
||||
C.ngx_hex_dump(b, s, len)
|
||||
return ffi_str(b, len * 2), true
|
||||
else
|
||||
return ffi_str(s, len), true
|
||||
end
|
||||
end
|
||||
|
||||
local function seed()
|
||||
local a,b,c,d = bytes(4):byte(1, 4)
|
||||
return randomseed(a * 0x1000000 + b * 0x10000 + c * 0x100 + d)
|
||||
end
|
||||
|
||||
local function number(min, max, reseed)
|
||||
if reseed then seed() end
|
||||
if min and max then return random(min, max)
|
||||
elseif min then return random(min)
|
||||
else return random() end
|
||||
end
|
||||
|
||||
local function token(len, chars, sep)
|
||||
chars = chars or alnum
|
||||
local count
|
||||
local token = new_tab(len, 0)
|
||||
if type(chars) ~= "table" then
|
||||
chars = tostring(chars)
|
||||
count = #chars
|
||||
local n
|
||||
for i=1,len do
|
||||
n = number(1, count)
|
||||
token[i] = chars:sub(n, n)
|
||||
end
|
||||
else
|
||||
count = #chars
|
||||
for i=1,len do token[i] = chars[number(1, count)] end
|
||||
end
|
||||
return concat(token, sep)
|
||||
end
|
||||
|
||||
seed()
|
||||
|
||||
return {
|
||||
bytes = bytes,
|
||||
number = number,
|
||||
token = token
|
||||
}
|
169
setup.sh
Normal file → Executable file
169
setup.sh
Normal file → Executable file
@ -3,15 +3,22 @@
|
||||
#OPTIONS!
|
||||
|
||||
MASTERONION="dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion"
|
||||
TORAUTHPASSWORD="password"
|
||||
TORAUTHPASSWORD="changethispassowrd"
|
||||
BACKENDONIONURL="biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion"
|
||||
|
||||
#set to true if you want to setup local proxy instead of proxy over Tor
|
||||
LOCALPROXY=false
|
||||
PROXYPASSURL="10.10.10.10:80"
|
||||
|
||||
#Shared Front Captcha Key. Key alphanumeric between 64-128. Salt needs to be exactly 8 chars.
|
||||
KEY="encryption_key"
|
||||
SALT="salt1234"
|
||||
SALT="1saltkey"
|
||||
SESSION_LENGTH=3600
|
||||
|
||||
#CSS Branding
|
||||
|
||||
HEXCOLOR="#9b59b6"
|
||||
SITENAME="dread"
|
||||
|
||||
#There is more branding you need to do in the resty/caphtml_d.lua file near the end.
|
||||
|
||||
@ -25,7 +32,7 @@ NC='\033[0m' # No Color
|
||||
printf "\r\nProvided by your lovely ${BLUE}/u/Paris${NC} from dread. \r\n"
|
||||
printf "with help from ${BLUE}/u/mr_white${NC} from whitehousemarket.\n"
|
||||
echo "For the full effects of the DDOS prevention you will need to make sure to setup v3 onionbalance."
|
||||
echo "Max 6-9 backend instances for each onion. This script will help make the backend instances."
|
||||
echo "Onionbalance v3 does have distinct descriptors in a forked version. Read the README.MD in the onionbalance folder for more information. "
|
||||
|
||||
if [ ${#MASTERONION} -lt 62 ]; then
|
||||
echo "MASTEWRONION doesn't have the correct length. The url needs to include the .onion at the end."
|
||||
@ -38,9 +45,18 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
echo "Proceeding to do the configuration and setup. This will take awhile."
|
||||
shopt -s nullglob dotglob
|
||||
directory=(dependencies/*)
|
||||
if [ ${#directory[@]} -gt 0 ]
|
||||
then
|
||||
echo "Dependency Folder Found!"
|
||||
else
|
||||
echo "You need to get the dependencies first. Run './getdependencies.sh'"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Proceeding to do the configuration and setup. This will take awhile."
|
||||
sleep 5
|
||||
|
||||
### Configuration
|
||||
string="s/masterbalanceonion/"
|
||||
@ -49,7 +65,17 @@ string+="/g"
|
||||
sed -i $string site.conf
|
||||
|
||||
string="s/torauthpassword/"
|
||||
string+="$torinput"
|
||||
string+="$TORAUTHPASSWORD"
|
||||
string+="/g"
|
||||
sed -i $string site.conf
|
||||
|
||||
string="s/backendurl/"
|
||||
string+="$BACKENDONIONURL"
|
||||
string+="/g"
|
||||
sed -i $string site.conf
|
||||
|
||||
string="s/proxypassurl/"
|
||||
string+="$PROXYPASSURL"
|
||||
string+="/g"
|
||||
sed -i $string site.conf
|
||||
|
||||
@ -63,16 +89,44 @@ string+="$SALT"
|
||||
string+="/g"
|
||||
sed -i $string lua/cap.lua
|
||||
|
||||
string="s/sessionconfigvalue/"
|
||||
string+="$SESSION_LENGTH"
|
||||
string+="/g"
|
||||
sed -i $string lua/cap.lua
|
||||
|
||||
string="s/HEXCOLOR/"
|
||||
string+="$HEXCOLOR"
|
||||
string+="/g"
|
||||
sed -i $string cap_d.css
|
||||
|
||||
string="s/HEXCOLOR/"
|
||||
string+="$HEXCOLOR"
|
||||
string+="/g"
|
||||
sed -i $string queue.html
|
||||
|
||||
string="s/SITENAME/"
|
||||
string+="$SITENAME"
|
||||
string+="/g"
|
||||
sed -i $string queue.html
|
||||
|
||||
string="s/SITENAME/"
|
||||
string+="$SITENAME"
|
||||
string+="/g"
|
||||
sed -i $string resty/caphtml_d.lua
|
||||
|
||||
if $LOCALPROXY
|
||||
then
|
||||
string="s/#proxy_pass/"
|
||||
string+="proxy_pass"
|
||||
string+="/g"
|
||||
sed -i $string site.conf
|
||||
else
|
||||
string="s/#socks_/"
|
||||
string+="socks_"
|
||||
string+="/g"
|
||||
sed -i $string site.conf
|
||||
fi
|
||||
|
||||
apt-get update
|
||||
apt-get install -y apt-transport-https lsb-release ca-certificates dirmngr
|
||||
|
||||
@ -84,44 +138,49 @@ echo "deb https://nginx.org/packages/debian/ buster nginx" > /etc/apt/sources.li
|
||||
|
||||
gpg --import A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc
|
||||
gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | apt-key add -
|
||||
|
||||
apt-key add nginx_signing.key
|
||||
|
||||
apt-get update
|
||||
apt-get install -y tor nyx nginx
|
||||
apt-get install -y vanguards
|
||||
apt-get install -y build-essential zlib1g-dev libpcre3 libpcre3-dev uuid-dev gcc git wget curl libgd3 libgd-dev
|
||||
|
||||
command="nginx -v"
|
||||
nginxv=$( ${command} 2>&1 )
|
||||
NGINXVERSION=$(echo $nginxv | grep -o '[0-9.]*$')
|
||||
|
||||
NGINXOPENSSL="1.1.1d"
|
||||
|
||||
wget https://nginx.org/download/nginx-$NGINXVERSION.tar.gz
|
||||
tar -xzvf nginx-$NGINXVERSION.tar.gz
|
||||
|
||||
cp -R dependencies/* nginx-$NGINXVERSION/
|
||||
|
||||
cd nginx-$NGINXVERSION
|
||||
|
||||
apt-get install -y build-essential zlib1g-dev libpcre3 libpcre3-dev uuid-dev gcc git wget curl libgd3 libgd-dev
|
||||
|
||||
git clone https://github.com/yorkane/socks-nginx-module.git
|
||||
git clone https://github.com/nbs-system/naxsi.git
|
||||
wget https://www.openssl.org/source/openssl-$NGINXOPENSSL.tar.gz
|
||||
tar -xzvf openssl-$NGINXOPENSSL.tar.gz
|
||||
git clone https://github.com/openresty/headers-more-nginx-module.git
|
||||
git clone https://github.com/openresty/echo-nginx-module.git
|
||||
|
||||
#some required stuff for lua/luajit. obviously versions should be ckecked with every install/update
|
||||
git clone https://github.com/openresty/lua-nginx-module
|
||||
cd lua-nginx-module
|
||||
git checkout v0.10.16
|
||||
cd ..
|
||||
git clone https://github.com/openresty/luajit2
|
||||
cd luajit2
|
||||
git checkout v2.1-20200102
|
||||
cd ..
|
||||
git clone https://github.com/vision5/ngx_devel_kit
|
||||
cd luajit2
|
||||
make -j8 && make install
|
||||
cd ..
|
||||
|
||||
cd lua-resty-string
|
||||
make install
|
||||
cd ..
|
||||
|
||||
cd lua-resty-cookie
|
||||
make install
|
||||
cd ..
|
||||
|
||||
cd lua-gd
|
||||
gcc -o gd.so -DGD_XPM -DGD_JPEG -DGD_FONTCONFIG -DGD_FREETYPE -DGD_PNG -DGD_GIF -O2 -Wall -fPIC -fomit-frame-pointer -I/usr/local/include/luajit-2.1 -DVERSION=\"2.0.33r3\" -shared -lgd luagd.c
|
||||
mv gd.so /usr/local/lib/lua/5.1/gd.so
|
||||
cd ..
|
||||
|
||||
cp -a lua-resty-session/lib/resty/session* /usr/local/lib/lua/resty/
|
||||
|
||||
export LUAJIT_LIB=/usr/local/lib
|
||||
export LUAJIT_INC=/usr/local/include/luajit-2.1
|
||||
./configure --with-cc-opt='-Wno-stringop-overflow -Wno-stringop-truncation -Wno-cast-function-type' \
|
||||
@ -135,67 +194,66 @@ export LUAJIT_INC=/usr/local/include/luajit-2.1
|
||||
--add-dynamic-module=ngx_devel_kit \
|
||||
--add-dynamic-module=lua-nginx-module
|
||||
|
||||
git clone https://github.com/openresty/lua-resty-string
|
||||
cd lua-resty-string
|
||||
make install
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/cloudflare/lua-resty-cookie
|
||||
cd lua-resty-cookie
|
||||
make install
|
||||
cd ..
|
||||
|
||||
git clone https://github.com/bungle/lua-resty-session
|
||||
cp -a lua-resty-session/lib/resty/session* /usr/local/lib/lua/resty/
|
||||
|
||||
git clone https://github.com/ittner/lua-gd/
|
||||
cd lua-gd
|
||||
gcc -o gd.so -DGD_XPM -DGD_JPEG -DGD_FONTCONFIG -DGD_FREETYPE -DGD_PNG -DGD_GIF -O2 -Wall -fPIC -fomit-frame-pointer -I/usr/local/include/luajit-2.1 -DVERSION=\"2.0.33r3\" -shared -lgd luagd.c
|
||||
mv gd.so /usr/local/lib/lua/5.1/gd.so
|
||||
cd ..
|
||||
|
||||
wget -O /usr/local/lib/lua/resty/aes_functions.lua https://github.com/c64bob/lua-resty-aes/raw/master/lib/resty/aes_functions.lua
|
||||
#https://github.com/c64bob/lua-resty-aes/raw/master/lib/resty/aes_functions.lua
|
||||
mv resty/aes_functions.lua /usr/local/lib/lua/resty/aes_functions.lua
|
||||
|
||||
mkdir /etc/nginx/resty/
|
||||
#include seems to be a bit mssed up with luajit
|
||||
mkdir /etc/nginx/resty
|
||||
ln -s /usr/local/lib/lua/resty/ /etc/nginx/resty/
|
||||
|
||||
make -j16 modules
|
||||
|
||||
cp -r objs modules
|
||||
rm -R /etc/nginx/modules
|
||||
mkdir /etc/nginx/modules
|
||||
mv modules /etc/nginx/modules
|
||||
cd ..
|
||||
|
||||
rm /etc/nginx/nginx.conf
|
||||
mv nginx.conf /etc/nginx/nginx.conf
|
||||
rm /etc/nginx/naxsi_core.rules
|
||||
mv naxsi_core.rules /etc/nginx/naxsi_core.rules
|
||||
rm /etc/nginx/naxsi_whitelist.rules
|
||||
mv naxsi_whitelist.rules /etc/nginx/naxsi_whitelist.rules
|
||||
rm -R /etc/nginx/lua/
|
||||
mv lua /etc/nginx/
|
||||
mv resty/* /etc/nginx/resty/resty/
|
||||
rm /etc/nginx/resty/caphtml_d.lua
|
||||
mv /etc/nginx/resty/resty/caphtml_d.lua /etc/nginx/resty/caphtml_d.lua
|
||||
rm /etc/nginx/resty/resty/random.lua
|
||||
mv random.lua /etc/nginx/resty/resty/random.lua
|
||||
mv queue.html /etc/nginx/queue.html
|
||||
rm -R /etc/nginx/sites-enabled/
|
||||
mkdir /etc/nginx/sites-enabled/
|
||||
mv site.conf /etc/nginx/sites-enabled/site.conf
|
||||
|
||||
#background generation
|
||||
apt-get install -y python3-pil
|
||||
mv gen_background.py /etc/nginx/gen_background.py
|
||||
echo "* * * * * root python3 /etc/nginx/gen_background.py" > /etc/cron.d/background-generate
|
||||
mv font.ttf /etc/nginx/font.ttf
|
||||
rm /etc/nginx/cap_d.css
|
||||
mv cap_d.css /etc/nginx/cap_d.css
|
||||
|
||||
chown -R www-data:www-data /etc/nginx/
|
||||
chown -R www-data:www-data /usr/local/lib/lua
|
||||
|
||||
chmod 755 startup.sh
|
||||
rm /startup.sh
|
||||
mv startup.sh /startup.sh
|
||||
chmod 755 rc.local
|
||||
rm /etc/rc.local
|
||||
mv rc.local /etc/rc.local
|
||||
|
||||
rm /etc/sysctl.conf
|
||||
mv sysctl.conf /etc/sysctl.conf
|
||||
|
||||
pkill tor
|
||||
|
||||
mv torrc /etc/tor/torrc
|
||||
|
||||
if $LOCALPROXY
|
||||
then
|
||||
echo "localproxy enabled"
|
||||
else
|
||||
mv torrc2 /etc/tor/torrc2
|
||||
mv torrc3 /etc/tor/torrc3
|
||||
fi
|
||||
|
||||
torhash=$(tor --hash-password $TORAUTHPASSWORD| tail -c 62)
|
||||
string="s/hashedpassword/"
|
||||
string+="$torhash"
|
||||
@ -215,7 +273,7 @@ string+="$HOSTNAME"
|
||||
string+="/g"
|
||||
sed -i $string /etc/nginx/sites-enabled/site.conf
|
||||
|
||||
echo "MasterOnionAddress $MASTERONION" >> /etc/tor/hidden_service/ob_config
|
||||
echo "MasterOnionAddress $MASTERONION" > /etc/tor/hidden_service/ob_config
|
||||
|
||||
pkill tor
|
||||
sleep 10
|
||||
@ -223,8 +281,19 @@ sleep 10
|
||||
sed -i "s/#HiddenServiceOnionBalanceInstance/HiddenServiceOnionBalanceInstance/g" /etc/tor/torrc
|
||||
|
||||
tor
|
||||
|
||||
if $LOCALPROXY
|
||||
then
|
||||
echo "localproxy enabled"
|
||||
else
|
||||
tor -f /etc/tor/torrc2
|
||||
tor -f /etc/tor/torrc3
|
||||
fi
|
||||
|
||||
nginx
|
||||
service vanguards start
|
||||
nginx -s stop
|
||||
nginx
|
||||
|
||||
clear
|
||||
|
||||
|
58
site.conf
58
site.conf
@ -6,13 +6,16 @@
|
||||
#keepalive 128; or proxy_bind on multiple local ips can be used to mitigate local port exhaustion
|
||||
#most likely with this setup it's not the case
|
||||
#if this runs on the same machine as the application server UNIX sockets should be used instead of TCP
|
||||
|
||||
upstream tor {
|
||||
server 127.0.0.1:9060;
|
||||
server 127.0.0.1:9070;
|
||||
}
|
||||
access_by_lua_no_postpone on;
|
||||
lua_package_path "/etc/nginx/resty/?.lua;;";
|
||||
|
||||
init_by_lua_block {
|
||||
allowed_hosts = { "mainonion",
|
||||
"masterbalanceonion"
|
||||
"dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion"
|
||||
}
|
||||
|
||||
function in_array(tab, val)
|
||||
@ -63,17 +66,18 @@ init_by_lua_block {
|
||||
|
||||
function kill_circuit(premature, clientip, headerip)
|
||||
local circuitid = calc_circuit(headerip)
|
||||
local sockfile = "unix:/etc/tor/c1"
|
||||
local response = "Closing circuit " .. circuitid .. " "
|
||||
local sock = ngx.socket.tcp()
|
||||
sock:settimeout(1000)
|
||||
local ok, err = sock:connect(clientip, 9051)
|
||||
local ok, err = sock:connect(sockfile)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to connect to tor: " .. err)
|
||||
return
|
||||
end
|
||||
ngx.log(ngx.ERR, "connected to tor")
|
||||
|
||||
local bytes, err = sock:send("authenticate \"torauthpassword\"\n")
|
||||
local bytes, err = sock:send("authenticate \"changethispassowrd\"\n")
|
||||
if not bytes then
|
||||
ngx.log(ngx.ERR, "failed authenticate to tor: " .. err)
|
||||
return
|
||||
@ -107,15 +111,15 @@ init_by_lua_block {
|
||||
#limiting by proxy_protocol_addr won't work with V2 onions and maybe should be disabled.
|
||||
#limiting by cookie_<name> works regarless and must be used, otherwise an attacker can solve a captcha by hand and add it to a script/bot
|
||||
|
||||
limit_req_zone $proxy_protocol_addr zone=circuits:50m rate=3r/s;
|
||||
limit_req_zone $cookie_dcap zone=capcookie:50m rate=3r/s;
|
||||
limit_req_zone $proxy_protocol_addr zone=circuits:50m rate=6r/s;
|
||||
limit_req_zone $cookie_dcap zone=capcookie:50m rate=6r/s;
|
||||
|
||||
#proxy_protocol only makes sense with V3 onions (exportcircuitid) otherwise it will break things.
|
||||
#kill_circuit won't be used without it
|
||||
server {
|
||||
listen 88 proxy_protocol backlog=16384;
|
||||
allow 127.0.0.1;
|
||||
deny all;
|
||||
listen unix:/etc/tor/nginx1 proxy_protocol bind;
|
||||
allow unix:;
|
||||
deny all;
|
||||
|
||||
#access_log /var/log/nginx/front_access.log;
|
||||
|
||||
@ -175,7 +179,7 @@ server {
|
||||
#naxsi seems to kick in before everything else except rate limiter but if it does trash traffic won't make it to the application servers anyway
|
||||
#doesn't make sense to blacklist cookie as it will annoy users
|
||||
|
||||
location = @waf {
|
||||
location @waf {
|
||||
error_log /var/log/nginx/front_error.log;
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
@ -204,6 +208,20 @@ server {
|
||||
}
|
||||
}
|
||||
|
||||
location @502 {
|
||||
default_type text/html;
|
||||
content_by_lua_block {
|
||||
ngx.say("<head><title>502 Timeout</title></head>")
|
||||
ngx.say("<body bgcolor=\"white\">")
|
||||
ngx.say("<center><h1>502 Timeout</h1></center>")
|
||||
ngx.say("<hr><center><p>It seems this endgame front doesn't have a stable connection to the backend right now.</p></center>")
|
||||
ngx.say("<center><p>To fix it you can try to reload the page. If that doesn't work, and you end back here, get a new circuit.</p></center>")
|
||||
ngx.say("<center><p>If getting a new circuit doesn't work. Try to get a brand new Tor identity.</p></center>")
|
||||
ngx.say("<center><p>If getting a new Tor identity doesn't work come back later.</p></center></body>")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
location /kill {
|
||||
access_by_lua_block {
|
||||
proxyip = "no_proxy"
|
||||
@ -242,15 +260,17 @@ server {
|
||||
error_log /var/log/nginx/front_error.log;
|
||||
|
||||
#rate limits per circuit ID (won't work with V2 and maybe should be disabled)
|
||||
limit_req zone=circuits burst=6 nodelay;
|
||||
limit_req zone=circuits burst=10 nodelay;
|
||||
error_page 503 =503 @ratelimit;
|
||||
|
||||
#rate limits based on captcha cookie. if an attacker or bot solves the capcha by hand and inputs the cookie in a script
|
||||
#the cookie will be blacklisted by all fronts (eventually) and subsequent requests dropped.
|
||||
|
||||
limit_req zone=capcookie burst=6 nodelay;
|
||||
limit_req zone=capcookie burst=10 nodelay;
|
||||
error_page 503 =503 @ratelimit;
|
||||
|
||||
error_page 502 =502 @502;
|
||||
|
||||
#check if access captca is solved and other things
|
||||
access_by_lua_file lua/cap.lua;
|
||||
|
||||
@ -265,12 +285,14 @@ server {
|
||||
include "/etc/nginx/naxsi_whitelist.rules";
|
||||
error_log /etc/nginx/naxsi.log;
|
||||
proxy_set_header Host $host;
|
||||
#socks_pass socks5://127.0.0.1:9050;
|
||||
#socks_set_host exampleprivatev3onion.onion;
|
||||
#socks_set_header Host $host;
|
||||
#socks_redirect off;
|
||||
#socks_http_version 1.1;
|
||||
proxy_pass http://10.10.10.10;
|
||||
socks_pass socks5://tor;
|
||||
socks_set_host biblemeowimkh3utujmhm6oh2oeb3ubjw2lpgeq3lahrfr2l6ev6zgyd.onion;
|
||||
socks_set_header Host $host;
|
||||
socks_redirect off;
|
||||
socks_http_version 1.1;
|
||||
socks_next_upstream error timeout invalid_header http_500 http_502 http_503;
|
||||
#proxy_pass http://10.10.10.10:80;
|
||||
|
||||
header_filter_by_lua_block {
|
||||
local cookie, err = cook:new()
|
||||
if not cookie then
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
tor
|
||||
tor -f /etc/tor/torrc2
|
||||
tor -f /etc/tor/torrc3
|
||||
service vanguards start
|
||||
exit 0
|
@ -58,8 +58,5 @@
|
||||
# Log Martian Packets
|
||||
#net.ipv4.conf.all.log_martians = 1
|
||||
#
|
||||
net.ipv6.conf.all.disable_ipv6 = 1
|
||||
net.ipv6.conf.default.disable_ipv6 = 1
|
||||
net.ipv6.conf.lo.disable_ipv6 = 1
|
||||
net.core.somaxconn=16384
|
||||
net.core.netdev_max_backlog=100000
|
12
torrc
12
torrc
@ -3,17 +3,13 @@
|
||||
# The instance servers run standard onion services. In Basic mode the
|
||||
# control port does not need to be enabled.
|
||||
#User debian-tor
|
||||
#DataDirectory /etc/tor/tor-data
|
||||
|
||||
# ControlPort 9051
|
||||
# CookieAuthentication 1
|
||||
#SocksPort 0
|
||||
DataDirectory /etc/tor/1/
|
||||
|
||||
RunAsDaemon 1
|
||||
|
||||
HiddenServiceDir /etc/tor/hidden_service
|
||||
HiddenServicePort 80 127.0.0.1:88
|
||||
HiddenServiceMaxStreams 8
|
||||
HiddenServicePort 80 unix:/etc/tor/nginx1
|
||||
HiddenServiceMaxStreams 15
|
||||
HiddenServiceMaxStreamsCloseCircuit 1
|
||||
HiddenServiceNumIntroductionPoints 3
|
||||
HiddenServiceExportCircuitID haproxy
|
||||
@ -21,5 +17,7 @@ HiddenServiceExportCircuitID haproxy
|
||||
|
||||
CookieAuthentication 1
|
||||
ControlPort 9051
|
||||
ControlPort unix:/etc/tor/c1 WorldWritable RelaxDirModeCheck
|
||||
SocksPort unix:/etc/tor/s1 WorldWritable RelaxDirModeCheck
|
||||
HashedControlPassword hashedpassword
|
||||
HardwareAccel 1
|
7
torrc2
Normal file
7
torrc2
Normal file
@ -0,0 +1,7 @@
|
||||
#User debian-tor
|
||||
DataDirectory /etc/tor/2/
|
||||
|
||||
RunAsDaemon 1
|
||||
SocksPort 9060
|
||||
ControlPort unix:/etc/tor/c2 WorldWritable RelaxDirModeCheck
|
||||
CookieAuthentication 1
|
Loading…
Reference in New Issue
Block a user