Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- flipper.lua
- -- Universal CC:Tweaked Pentesting Tool
- -- Single-file design for ender pocket computers
- -- ============================================
- -- CONFIGURATION
- -- ============================================
- local DATA_FILE = ".flipper_data"
- local VERSION = "1.0"
- -- ============================================
- -- GLOBALS
- -- ============================================
- local modem = peripheral.find("modem")
- if not modem then
- print("No modem found!")
- return
- end
- local data = {
- targets = {},
- captured = {},
- settings = { autoSave = true }
- }
- local isJamming = false
- local openChannels = {}
- -- ============================================
- -- CLEANUP - Close ALL channels on startup
- -- Fixes "too many open channels" error
- -- ============================================
- local function cleanupChannels()
- for i = 1, 65535 do
- pcall(function() modem.close(i) end)
- end
- end
- -- Run cleanup immediately on load
- cleanupChannels()
- -- ============================================
- -- UTILITY FUNCTIONS
- -- ============================================
- local function clear()
- term.clear()
- term.setCursorPos(1, 1)
- end
- local function color(c)
- if term.isColor() then term.setTextColor(c) end
- end
- local function header(title)
- clear()
- local w = term.getSize()
- color(colors.cyan)
- print(string.rep("=", w))
- local pad = math.floor((w - #title - 4) / 2)
- print(string.rep(" ", pad) .. "[ " .. title .. " ]")
- print(string.rep("=", w))
- color(colors.white)
- end
- local function prompt(msg)
- color(colors.gray)
- write(msg or "> ")
- color(colors.white)
- return read()
- end
- local function pause()
- color(colors.gray)
- print("\nPress any key...")
- os.pullEvent("key")
- end
- local function saveData()
- local f = fs.open(DATA_FILE, "w")
- f.write(textutils.serialize(data))
- f.close()
- end
- local function loadData()
- if fs.exists(DATA_FILE) then
- local f = fs.open(DATA_FILE, "r")
- local content = f.readAll()
- f.close()
- data = textutils.unserialize(content) or data
- end
- end
- -- Deep scan a message for interesting fields
- local function analyzeMessage(msg)
- local flags = {}
- if type(msg) ~= "table" then return flags end
- local function scan(t, depth)
- if depth > 5 then return end
- for k, v in pairs(t) do
- local kl = tostring(k):lower()
- if kl:find("password") or kl:find("pass") or kl:find("pw") then
- table.insert(flags, "CRED:" .. tostring(v))
- elseif kl:find("secret") or kl:find("token") or kl:find("key") then
- table.insert(flags, "SECRET:" .. tostring(v))
- elseif kl == "command" or kl == "action" or kl == "type" then
- table.insert(flags, "CMD:" .. tostring(v))
- end
- if type(v) == "table" then scan(v, depth + 1) end
- end
- end
- scan(msg, 0)
- return flags
- end
- local function formatMessage(msg)
- if type(msg) == "table" then
- return textutils.serialize(msg):gsub("\n", " "):sub(1, 50)
- end
- return tostring(msg):sub(1, 50)
- end
- -- ============================================
- -- SCAN MODE
- -- ============================================
- local function modeScan()
- header("SCAN")
- print("Scan for active channels & devices\n")
- print("[1] Quick Scan (1-100, 2469)")
- print("[2] Full Scan (1-65535)")
- print("[3] Custom Range")
- print("[B] Back")
- local choice = prompt()
- local ranges = {}
- if choice == "1" then
- for i = 1, 100 do table.insert(ranges, i) end
- table.insert(ranges, 2469)
- table.insert(ranges, 65533)
- table.insert(ranges, 65535)
- elseif choice == "2" then
- for i = 1, 65535 do table.insert(ranges, i) end
- elseif choice == "3" then
- print("Enter start channel:")
- local s = tonumber(prompt()) or 1
- print("Enter end channel:")
- local e = tonumber(prompt()) or 100
- for i = s, e do table.insert(ranges, i) end
- else
- return
- end
- header("SCANNING...")
- local found = {}
- -- Open channels in batches of 128
- local batch = {}
- for i, ch in ipairs(ranges) do
- table.insert(batch, ch)
- if #batch >= 128 or i == #ranges then
- -- Open batch
- for _, c in ipairs(batch) do
- modem.open(c)
- end
- -- Send ping on each
- for _, c in ipairs(batch) do
- modem.transmit(c, c, "ping")
- modem.transmit(c, c, {type = "ping"})
- modem.transmit(c, c, {command = "ping"})
- end
- -- Listen briefly
- local timer = os.startTimer(0.5)
- while true do
- local event, p1, p2, p3, p4, p5 = os.pullEvent()
- if event == "modem_message" then
- local ch, reply, msg = p2, p3, p4
- if not found[ch] then found[ch] = {} end
- table.insert(found[ch], {reply = reply, msg = msg})
- elseif event == "timer" and p1 == timer then
- break
- end
- end
- -- Close batch
- for _, c in ipairs(batch) do
- modem.close(c)
- end
- batch = {}
- -- Progress
- term.setCursorPos(1, 5)
- term.clearLine()
- print("Scanned: " .. i .. "/" .. #ranges)
- end
- end
- -- Display results
- header("SCAN RESULTS")
- local count = 0
- for ch, responses in pairs(found) do
- count = count + 1
- color(colors.lime)
- write("Ch " .. ch .. ": ")
- color(colors.white)
- print(#responses .. " response(s)")
- for _, r in ipairs(responses) do
- local flags = analyzeMessage(r.msg)
- local dtype = "unknown"
- if type(r.msg) == "table" then
- if r.msg.command == "pong" then dtype = "turtle"
- elseif r.msg.type then dtype = r.msg.type
- elseif r.msg.action then dtype = r.msg.action
- end
- end
- -- Save target
- table.insert(data.targets, {
- channel = ch,
- replyId = r.reply,
- type = dtype,
- lastSeen = os.epoch("utc"),
- sample = r.msg
- })
- end
- if count >= 15 then
- print("... and more")
- break
- end
- end
- if count == 0 then
- print("No responses detected.")
- else
- print("\n" .. count .. " active channel(s) found")
- if data.settings.autoSave then saveData() end
- end
- pause()
- end
- -- ============================================
- -- SNIFF MODE
- -- ============================================
- local function modeSniff()
- header("SNIFF")
- print("Monitor traffic on channel(s)\n")
- print("[1] Single Channel")
- print("[2] Multi-Channel (up to 128)")
- print("[3] Common Channels (1,2,5,2469)")
- print("[B] Back")
- local choice = prompt()
- local channels = {}
- if choice == "1" then
- print("Enter channel:")
- local ch = tonumber(prompt())
- if ch then table.insert(channels, ch) end
- elseif choice == "2" then
- print("Enter channels (comma-separated):")
- local input = prompt()
- for num in input:gmatch("%d+") do
- table.insert(channels, tonumber(num))
- if #channels >= 128 then break end
- end
- elseif choice == "3" then
- channels = {1, 2, 5, 2469, 65535}
- else
- return
- end
- if #channels == 0 then return end
- -- Open channels
- for _, ch in ipairs(channels) do
- modem.open(ch)
- end
- header("SNIFFING - Press Q to stop")
- print("Channels: " .. table.concat(channels, ", ") .. "\n")
- local captureCount = 0
- while true do
- local event, p1, p2, p3, p4, p5 = os.pullEvent()
- if event == "modem_message" then
- local ch, reply, msg, dist = p2, p3, p4, p5
- captureCount = captureCount + 1
- local flags = analyzeMessage(msg)
- local flagStr = #flags > 0 and " " .. table.concat(flags, " ") or ""
- -- Color based on content
- if flagStr:find("CRED") then
- color(colors.red)
- elseif flagStr:find("SECRET") then
- color(colors.orange)
- elseif flagStr:find("CMD") then
- color(colors.yellow)
- else
- color(colors.lightGray)
- end
- local time = textutils.formatTime(os.time(), true)
- print("[" .. time .. "] Ch" .. ch .. " ID:" .. reply)
- color(colors.white)
- print(" " .. formatMessage(msg))
- if #flags > 0 then
- color(colors.red)
- print(" ^^ " .. table.concat(flags, " "))
- color(colors.white)
- end
- -- Store capture
- table.insert(data.captured, {
- time = os.epoch("utc"),
- channel = ch,
- sender = reply,
- message = msg,
- flags = flags
- })
- elseif event == "key" then
- if p1 == keys.q then break end
- end
- end
- -- Close channels
- for _, ch in ipairs(channels) do
- modem.close(ch)
- end
- print("\nCaptured " .. captureCount .. " messages")
- if data.settings.autoSave and captureCount > 0 then saveData() end
- pause()
- end
- -- ============================================
- -- ATTACK MODE
- -- ============================================
- local function modeAttack()
- header("ATTACK")
- print("Targeted exploits\n")
- print("[1] Replay - Resend captured message")
- print("[2] Inject - Send custom message")
- print("[3] Spoof - Forge sender ID")
- print("[4] Flood - DoS a channel")
- print("[B] Back")
- local choice = prompt()
- if choice == "1" then
- -- Replay
- header("REPLAY")
- if #data.captured == 0 then
- print("No captured messages to replay.")
- pause()
- return
- end
- print("Recent captures:")
- local start = math.max(1, #data.captured - 9)
- for i = start, #data.captured do
- local c = data.captured[i]
- print("[" .. i .. "] Ch" .. c.channel .. " -> " .. formatMessage(c.message):sub(1,30))
- end
- print("\nEnter # to replay (or B to back):")
- local idx = tonumber(prompt())
- if idx and data.captured[idx] then
- local cap = data.captured[idx]
- modem.open(cap.channel)
- modem.transmit(cap.channel, cap.sender, cap.message)
- modem.close(cap.channel)
- color(colors.lime)
- print("Replayed to channel " .. cap.channel)
- color(colors.white)
- end
- pause()
- elseif choice == "2" then
- -- Inject
- header("INJECT")
- print("Enter target channel:")
- local ch = tonumber(prompt())
- if not ch then return end
- print("Enter message (Lua table or string):")
- local input = prompt()
- local msg = loadstring("return " .. input)
- if msg then
- msg = msg()
- else
- msg = input
- end
- print("Enter reply channel (default: " .. ch .. "):")
- local reply = tonumber(prompt()) or ch
- modem.open(ch)
- modem.transmit(ch, reply, msg)
- modem.close(ch)
- color(colors.lime)
- print("Injected message to channel " .. ch)
- color(colors.white)
- pause()
- elseif choice == "3" then
- -- Spoof
- header("SPOOF")
- print("Send message with forged sender ID\n")
- print("Enter target channel:")
- local ch = tonumber(prompt())
- if not ch then return end
- print("Enter spoofed sender ID:")
- local spoofId = tonumber(prompt()) or 0
- print("Enter message (Lua table or string):")
- local input = prompt()
- local msg = loadstring("return " .. input)
- if msg then
- msg = msg()
- else
- msg = input
- end
- modem.open(ch)
- modem.transmit(ch, spoofId, msg)
- modem.close(ch)
- color(colors.lime)
- print("Sent with spoofed ID " .. spoofId .. " to channel " .. ch)
- color(colors.white)
- pause()
- elseif choice == "4" then
- -- Flood
- header("FLOOD")
- print("DoS attack on channel\n")
- print("Enter target channel:")
- local ch = tonumber(prompt())
- if not ch then return end
- print("Enter duration (seconds, max 60):")
- local duration = math.min(tonumber(prompt()) or 5, 60)
- print("\nFlooding channel " .. ch .. " for " .. duration .. "s...")
- print("Press any key to stop early.\n")
- modem.open(ch)
- local endTime = os.clock() + duration
- local count = 0
- while os.clock() < endTime do
- for i = 1, 50 do
- modem.transmit(ch, math.random(1, 65535), {
- garbage = string.rep("X", 100),
- rand = math.random(),
- ts = os.epoch("utc")
- })
- count = count + 1
- end
- term.setCursorPos(1, 8)
- term.clearLine()
- print("Sent: " .. count .. " packets")
- local timer = os.startTimer(0.05)
- while true do
- local event, p1 = os.pullEvent()
- if event == "key" then
- modem.close(ch)
- print("\nStopped. Total: " .. count)
- pause()
- return
- elseif event == "timer" and p1 == timer then
- break
- end
- end
- end
- modem.close(ch)
- color(colors.lime)
- print("\nComplete. Sent " .. count .. " packets")
- color(colors.white)
- pause()
- end
- end
- -- ============================================
- -- JAM MODE
- -- ============================================
- local function modeJam()
- header("JAM")
- print("Disrupt ALL wireless communications\n")
- print("[1] Jam ALL channels (rotating)")
- print("[2] Jam Common (1-100, 2469)")
- print("[3] Jam Specific channels")
- print("[B] Back")
- local choice = prompt()
- local channels = {}
- if choice == "1" then
- -- Will rotate through all
- channels = "all"
- elseif choice == "2" then
- for i = 1, 100 do table.insert(channels, i) end
- table.insert(channels, 2469)
- table.insert(channels, 65533)
- table.insert(channels, 65535)
- elseif choice == "3" then
- print("Enter channels (comma-separated):")
- local input = prompt()
- for num in input:gmatch("%d+") do
- table.insert(channels, tonumber(num))
- end
- else
- return
- end
- header("JAMMING...")
- print("Press any key to STOP\n")
- isJamming = true
- local count = 0
- local currentBatch = 1
- while isJamming do
- local batch = {}
- if channels == "all" then
- -- Rotate through all channels in batches of 128
- local start = ((currentBatch - 1) * 128) + 1
- local stop = math.min(start + 127, 65535)
- for i = start, stop do
- table.insert(batch, i)
- end
- currentBatch = currentBatch + 1
- if currentBatch * 128 > 65535 then currentBatch = 1 end
- else
- batch = channels
- end
- -- Open batch
- for _, ch in ipairs(batch) do
- pcall(function() modem.open(ch) end)
- end
- -- Flood
- for _, ch in ipairs(batch) do
- modem.transmit(ch, math.random(1, 65535), {
- j = string.rep("X", 200),
- r = math.random()
- })
- count = count + 1
- end
- -- Close batch
- for _, ch in ipairs(batch) do
- pcall(function() modem.close(ch) end)
- end
- -- Update display
- term.setCursorPos(1, 5)
- term.clearLine()
- if channels == "all" then
- print("Batch: " .. currentBatch .. "/512 | Packets: " .. count)
- else
- print("Packets sent: " .. count)
- end
- -- Check for key press
- local timer = os.startTimer(0.02)
- while true do
- local event, p1 = os.pullEvent()
- if event == "key" then
- isJamming = false
- break
- elseif event == "timer" and p1 == timer then
- break
- end
- end
- end
- color(colors.lime)
- print("\nJamming stopped. Sent " .. count .. " packets")
- color(colors.white)
- pause()
- end
- -- ============================================
- -- TARGETS VIEW
- -- ============================================
- local function modeTargets()
- header("TARGETS")
- if #data.targets == 0 then
- print("No targets discovered yet.")
- print("Run SCAN first.")
- pause()
- return
- end
- print("Discovered devices:\n")
- local shown = math.min(#data.targets, 15)
- for i = #data.targets - shown + 1, #data.targets do
- local t = data.targets[i]
- color(colors.yellow)
- write("[" .. i .. "] ")
- color(colors.white)
- print("Ch:" .. t.channel .. " ID:" .. (t.replyId or "?") .. " Type:" .. (t.type or "?"))
- end
- print("\n[C] Clear all | [B] Back")
- local choice = prompt()
- if choice:lower() == "c" then
- data.targets = {}
- saveData()
- print("Cleared.")
- sleep(0.5)
- end
- end
- -- ============================================
- -- MAIN MENU
- -- ============================================
- local function mainMenu()
- loadData()
- while true do
- header("FLIPPER CC v" .. VERSION)
- local w = term.getSize()
- print("")
- print(" [1] SCAN - Find devices")
- print(" [2] SNIFF - Monitor traffic")
- print(" [3] ATTACK - Targeted exploits")
- print(" [4] JAM - Block all comms")
- print("")
- print(" [T] Targets (" .. #data.targets .. " saved)")
- print(" [C] Captured (" .. #data.captured .. " msgs)")
- print(" [Q] Quit")
- print("")
- local choice = prompt()
- if choice == "1" then
- modeScan()
- elseif choice == "2" then
- modeSniff()
- elseif choice == "3" then
- modeAttack()
- elseif choice == "4" then
- modeJam()
- elseif choice:lower() == "t" then
- modeTargets()
- elseif choice:lower() == "c" then
- header("CAPTURED")
- if #data.captured == 0 then
- print("No captured messages.")
- else
- local start = math.max(1, #data.captured - 10)
- for i = start, #data.captured do
- local c = data.captured[i]
- print("[" .. i .. "] Ch" .. c.channel .. ": " .. formatMessage(c.message):sub(1,35))
- end
- end
- print("\n[X] Clear all | [B] Back")
- if prompt():lower() == "x" then
- data.captured = {}
- saveData()
- end
- elseif choice:lower() == "q" then
- saveData()
- cleanupChannels() -- Ensure all channels closed
- clear()
- print("Flipper CC closed.")
- return
- end
- end
- end
- -- ============================================
- -- ENTRY POINT
- -- ============================================
- mainMenu()
Advertisement