altered-script-flow #1
@ -1,6 +1,8 @@
|
||||
.. _boot-chain-label:
|
||||
=======
|
||||
Booting
|
||||
=======
|
||||
|
||||
After exploitation the goal is to fully boot the device.
|
||||
|
||||
Current boot chain:
|
||||
|
@ -15,12 +15,40 @@ Samsung Firmware
|
||||
----------------
|
||||
Samsung releases firmware files for their devices. These files contain the bootloader, modem, and other firmware files.
|
||||
To see how the ROM works we are interested in the sboot firmware, which contains multiple stages of the bootloader.
|
||||
|
||||
To extract the sboot.bin file from a samsung firmware file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ unzip -p firmware.zip 'BL_*.tar.md5' | tar -Oxf - 'sboot.bin.lz4' | lz4 -d - sboot.bin
|
||||
|
||||
Frederic has also written a payload to extract the sboot.bin file from a connected samsung device (See: :ref:`boot-chain-label`). The extracted boots can be split up in different stages. We're provied with sboot 1-4.bin. Running strings then provides us with some information about each stage.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ strings -n4 sboot.bin.1.bin
|
||||
|
||||
was
|
||||
|
||||
.. list-table:: bootrom stages
|
||||
:header-rows: 1
|
||||
|
||||
* - File
|
||||
- Strings output
|
||||
- Likely boot stage?
|
||||
* - sboot.bin.1.bin
|
||||
- Exynos BL1
|
||||
- BL1
|
||||
* - sboot.bin.2.bin
|
||||
- BL31 %s
|
||||
- BL31
|
||||
* - sboot.bin.3.bin
|
||||
- Unsure. Contains strings like: TOP_DIV_ACLK_MFC_600 and APOLLO_DIV_APOLLO_RUN_MONITOR
|
||||
- BL2?
|
||||
* - sboot.bin.4.bin
|
||||
- Contains more textual information, and references to post BL2 boot, and android information
|
||||
- Kernel boot/BL33?
|
||||
|
||||
Memory Layout
|
||||
-------------
|
||||
TODO make memory layout of ROM, IMEM and some devices @JONHE
|
||||
|
11
source/exploit/.vscode/launch.json
vendored
11
source/exploit/.vscode/launch.json
vendored
@ -10,7 +10,7 @@
|
||||
"request": "launch",
|
||||
"program": "exploit.py",
|
||||
"console": "integratedTerminal",
|
||||
"args": ["--usb-debug"]
|
||||
"args": ["--debug"]
|
||||
},
|
||||
{
|
||||
"name": "Run boot chain",
|
||||
@ -19,15 +19,6 @@
|
||||
"program": "exploit.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
"args": ["--run-boot-chain"]
|
||||
},
|
||||
{
|
||||
"name": "Debug on device",
|
||||
"type": "debugpy",
|
||||
"request": "launch",
|
||||
"program": "exploit.py",
|
||||
"console": "integratedTerminal",
|
||||
"justMyCode": false,
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
|
@ -5,7 +5,7 @@ from ghidra_assistant.utils.utils import *
|
||||
from ghidra_assistant.concrete_device import *
|
||||
from ghidra_assistant.utils.debugger.debugger_archs.ga_arm64 import GA_arm64_debugger
|
||||
from qiling.const import QL_ARCH
|
||||
import os
|
||||
import os, tqdm, datetime
|
||||
|
||||
def p32(x):
|
||||
return struct.pack("<I", x)
|
||||
@ -56,7 +56,6 @@ class ExynosDevice():
|
||||
self.target = "8890" # TODO auto detect device
|
||||
self.connect_device()
|
||||
|
||||
|
||||
def connect_device(self):
|
||||
"""Setup proper connection, and ensure the connection is alive"""
|
||||
self.context = usb1.USBContext()
|
||||
@ -81,21 +80,18 @@ class ExynosDevice():
|
||||
raise e
|
||||
print(f"Connected device! {hex(self.idVendor)} {hex(self.idProduct)}")
|
||||
|
||||
|
||||
def write(self, data):
|
||||
transferred = ctypes.c_int()
|
||||
res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, data, len(data), ctypes.byref(transferred), 0)
|
||||
assert(res == 0), "Could not perform bulk transfer"
|
||||
return res
|
||||
|
||||
|
||||
def send_empty_transfer(self):
|
||||
transferred = ctypes.c_int()
|
||||
res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, 0, 0, ctypes.byref(transferred), 0)
|
||||
assert(res == 0)
|
||||
return transferred.value
|
||||
|
||||
|
||||
def test_bug_2(self):
|
||||
"""Interger overflow in last packet if reamining size is 1."""
|
||||
transferred = ctypes.c_int()
|
||||
@ -113,7 +109,6 @@ class ExynosDevice():
|
||||
while True:
|
||||
res = libusb1.libusb_bulk_transfer(self.handle._USBDeviceHandle__handle, ENDPOINT_BULK_OUT, payload, len(payload), ctypes.byref(transferred), 10)
|
||||
|
||||
|
||||
def test_bug(self):
|
||||
# Start by sending a valid packet
|
||||
# Integer overflow in the size field
|
||||
@ -141,7 +136,6 @@ class ExynosDevice():
|
||||
assert res == 0, "Error sending payload"
|
||||
pass
|
||||
|
||||
|
||||
def exploit(self, payload: bytes):
|
||||
'''
|
||||
Exploit the Exynos device, payload of 502 bytes max. This will send stage1 payload.
|
||||
@ -227,10 +221,9 @@ class ExynosDevice():
|
||||
#Overwrite all calls to make the concrete target function properly
|
||||
concrete_device.copy_functions()
|
||||
|
||||
|
||||
def usb_debug(self):
|
||||
"""
|
||||
Function to debug USB behaviour
|
||||
Function to debug USB behaviour. Sends and receives data in continuous flow.
|
||||
"""
|
||||
transferred = ctypes.c_int()
|
||||
# Send some data
|
||||
@ -254,6 +247,71 @@ class ExynosDevice():
|
||||
_recv_data()
|
||||
count += 1
|
||||
|
||||
def dump_memory(self, start: hex=0x0, end: hex=0x0206ffff, write=False):
|
||||
"""
|
||||
Dumps memory from the device.
|
||||
|
||||
Transfer XFER_BUFFER at 0x02021800, to: 0x02020F08. End of memory at 0x0206ffff.
|
||||
"""
|
||||
# NOT WORKING YET
|
||||
transferred = ctypes.c_int()
|
||||
dumped = b""
|
||||
# Read data from memory
|
||||
for block in tqdm.tqdm(range(start, end, 0x200)):
|
||||
self.usb_write(p32(block-0x200))
|
||||
res = self.usb_read(0x200)
|
||||
dumped += res
|
||||
|
||||
if write:
|
||||
filename = f"dump_{hex(start)}_{hex(end)}_{self.target}_{datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}.bin"
|
||||
with open(filename, "wb") as f:
|
||||
f.write(dumped)
|
||||
return dumped
|
||||
|
||||
# transferred = ctypes.c_int()
|
||||
# stack_pointer = 0x02021810
|
||||
# for block in range(0x2020000, 0x2200000, 0x200):
|
||||
# stack_pointer += 0x200
|
||||
# dumped += self.cd.memdump_region(block, 0x200)
|
||||
|
||||
def setup_guppy_debugger(self):
|
||||
"""
|
||||
Sets up guppy debugger on the device itself.
|
||||
"""
|
||||
|
||||
def _setup_debugger():
|
||||
'''
|
||||
Setup the debugger as a concrete device
|
||||
'''
|
||||
self.cd = ConcreteDevice(None, False)
|
||||
self.cd.dev = self.setup_concrete_device(self.cd)
|
||||
self.cd.test_connection()
|
||||
|
||||
|
||||
def _initial_run_debugger():
|
||||
"""Write debugger to device and test basic functionality"""
|
||||
if os.getenv("USER") == "eljakim":
|
||||
debugger = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/debugger.bin", "rb").read()
|
||||
else:
|
||||
try:
|
||||
debugger = open("../../dump/debugger.bin", "rb").read()
|
||||
except Exception as e:
|
||||
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
|
||||
sys.exit(0)
|
||||
debugger += ((0x2000 - len(debugger)) * b"\x00")
|
||||
assert len(debugger) == 0x2000, "Invalid debugger size, stage1 requires 0x2000 size"
|
||||
for block in range(0, len(debugger), 0x200):
|
||||
self.usb_write(debugger[block:block+0x200])
|
||||
# time.sleep(.5) # Wait a little bit
|
||||
assert self.usb_read(0x200) == b"GiAs", "No response from debugger"
|
||||
|
||||
# Test basic functionality
|
||||
self.usb_write(b"PING")
|
||||
r = self.usb_read(0x200)
|
||||
assert r == b"PONG", f"Invalid response from device: {r}"
|
||||
|
||||
_initial_run_debugger()
|
||||
_setup_debugger()
|
||||
|
||||
def dumb_interact(self):
|
||||
'''
|
||||
@ -265,7 +323,14 @@ class ExynosDevice():
|
||||
|
||||
def relocate_debugger():
|
||||
# Seems to be cleared upon cache clearing??
|
||||
debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/reloc_debugger.bin", "rb").read()
|
||||
if os.getenv("USER") == "eljakim":
|
||||
debugger_reloc = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/debugger.bin", "rb").read()
|
||||
else:
|
||||
try:
|
||||
debugger_reloc = open("../../dump/debugger.bin", "rb").read()
|
||||
except Exception as e:
|
||||
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
|
||||
sys.exit(0)
|
||||
self.cd.memwrite_region(0x020c0000, debugger_reloc)
|
||||
self.usb_write(b"FLSH") # Flush cache
|
||||
self.cd.restore_stack_and_jump(0x020c0000)
|
||||
@ -348,63 +413,20 @@ class ExynosDevice():
|
||||
pass
|
||||
|
||||
|
||||
def setup_guppy_debugger(self):
|
||||
"""
|
||||
Run the boot chain for the Exynos device.
|
||||
|
||||
Load and send stage1 payload - exploit (stage1)
|
||||
"""
|
||||
|
||||
def _setup_debugger():
|
||||
'''
|
||||
Setup the debugger as a concrete device
|
||||
'''
|
||||
self.cd = ConcreteDevice(None, False)
|
||||
self.cd.dev = self.setup_concrete_device(self.cd)
|
||||
self.cd.test_connection()
|
||||
|
||||
|
||||
def _initial_run_debugger():
|
||||
"""Write debugger to device and test basic functionality"""
|
||||
if os.getenv("USER") == "eljakim":
|
||||
debugger = open("/home/eljakim/Source/gupje/source/bin/samsung_s7/debugger.bin", "rb").read()
|
||||
else:
|
||||
try:
|
||||
debugger = open("../../dump/debugger.bin", "rb").read()
|
||||
except Exception as e:
|
||||
print(f'Are you missing your debugger? Please ensure it is present in dump/debugger.bin. {e}')
|
||||
sys.exit(0)
|
||||
debugger += ((0x2000 - len(debugger)) * b"\x00")
|
||||
assert len(debugger) == 0x2000, "Invalid debugger size, stage1 requires 0x2000 size"
|
||||
for block in range(0, len(debugger), 0x200):
|
||||
self.usb_write(debugger[block:block+0x200])
|
||||
# time.sleep(.5) # Wait a little bit
|
||||
assert self.usb_read(0x200) == b"GiAs", "No response from debugger"
|
||||
|
||||
# Test basic functionality
|
||||
self.usb_write(b"PING")
|
||||
r = self.usb_read(0x200)
|
||||
assert r == b"PONG", f"Invalid response from device: {r}"
|
||||
|
||||
_initial_run_debugger()
|
||||
_setup_debugger()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
arg = argparse.ArgumentParser("Exynos exploit")
|
||||
arg.add_argument("--usb-debug", action="store_true", help="Debug USB stack", default=False)
|
||||
arg.add_argument("--run-boot-chain", action="store_true", help="Run boot chain to boot different boot stages", default=False)
|
||||
arg.add_argument("--dumb-debug", action="store_true", help="Live debugging on device", default=True)
|
||||
arg.add_argument("--debug", action="store_true", help="Debug USB stack", default=False)
|
||||
args = arg.parse_args()
|
||||
|
||||
exynos = ExynosDevice()
|
||||
|
||||
if args.usb_debug:
|
||||
if args.debug:
|
||||
shellcode = open("../dwc3_test/dwc3.bin", "rb").read()
|
||||
exynos.exploit(shellcode)
|
||||
exynos.usb_debug()
|
||||
exynos.dump_memory(write=True)
|
||||
# exynos.usb_debug()
|
||||
sys.exit(0)
|
||||
|
||||
elif args.run_boot_chain:
|
||||
stage1 = open("stage1/stage1.bin", "rb").read()
|
||||
exynos.exploit(stage1)
|
||||
exynos.setup_guppy_debugger()
|
||||
|
Loading…
Reference in New Issue
Block a user