redballoonsecurity / ofrak

OFRAK: unpack, modify, and repack binaries.
https://ofrak.com
Other
1.85k stars 127 forks source link

CPIO Unpacker no work on local Linux (not container, local). #275

Closed gskip17 closed 1 year ago

gskip17 commented 1 year ago

What is the problem? (Here is where you provide a complete Traceback.)

OFRAK relies on the cpio utility to unpack CPIO filesystems. The utility is called with -id flags. When unpacking the filesystem, if there are any absolute filepaths, the utility will crash because it should (rightly) not try and overwrite a user's system files.

ofrak.service.job_service_i.ComponentAutoRunFailure: Component CpioUnpacker failed when running on e1348bce32ac4798a453715762d4898b. Component was chosen because it matched filters (((ComponentTypeFilter(Unpacker) or ComponentTypeFilter(Identifier))) and ((ComponentTypeFilter(Identifier) and ComponentTargetFilter(FilesystemRoot, CpioFilesystem)) or (not ComponentTypeFilter(Identifier) and (ComponentTargetFilter(CpioFilesystem) then ComponentTargetFilter(FilesystemRoot)))))

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/dist-packages/ofrak/gui/server.py", line 95, in wrapper
    return await func(*args, **kwargs)
  File "/usr/local/lib/python3.10/dist-packages/ofrak/gui/server.py", line 303, in unpack
    result = await resource.unpack()
  File "/usr/local/lib/python3.10/dist-packages/ofrak/resource.py", line 412, in unpack
    return await self.auto_run(all_identifiers=True, all_unpackers=True)
  File "/usr/local/lib/python3.10/dist-packages/ofrak/resource.py", line 385, in auto_run
    components_result = await self._job_service.run_components(
  File "/usr/local/lib/python3.10/dist-packages/ofrak/service/job_service.py", line 262, in run_components
    individual_component_results = await self._auto_run_components(
  File "/usr/local/lib/python3.10/dist-packages/ofrak/service/job_service.py", line 456, in _auto_run_components
    raise component_run_error from ComponentAutoRunFailure(
  File "/usr/local/lib/python3.10/dist-packages/ofrak/service/job_service.py", line 133, in _run_component
    result = await component.run(
  File "/usr/local/lib/python3.10/dist-packages/ofrak/component/abstract.py", line 103, in run
    raise ComponentSubprocessError(e)
ofrak.component.abstract.ComponentSubprocessError: Command '['cpio', '-id']' returned non-zero exit status 2.
Stderr: None.
Stdout: None.

Please provide some information about your environment. At minimum we would like the following information on your platform and Python environment:

If you've discovered it, what is the root cause of the problem?

See above.

How often does the issue happen?

Every time a CPIO filesystem unpacks, on Linux.

What are the steps to reproduce the issue?

Unpack a CPIO filesystem on a Linux distro. It will work in the ofrak docker container (supposedly?).

Ideally, give us a short script that reproduces the issue.

Open a DTB or something similar containing a CPIO filesystem, and unpack it recursively. await resource.unpack_recursively()

Here is one you can try out. image.zip

How would you implement this fix?

A possible solution is to include the --no-absolute-filenames flag, however this will mean you will potentially lose files during repacking.

A better solution is to probably just use the 7z utility to unpack the filesystem. This is what the unblob project appears to do and I tested it on my machine and it seems like a decent solution. Using 7z is also a bit safer in this scenario.

Are there any (reasonable) alternative approaches?

Are you interested in implementing it yourself?

Yes. Working on a fix.

gskip17 commented 1 year ago

Ok, so the problem is that during unpacking, when there is a file with an absolute path, the OS will (correctly) realize it should not try and overwrite that specific file (eg /dev/console), and throw an error to stderr for that specific file.

If you prevent the script from checking the return code, it will successfully run cpio -id to completion.

(ofrak/core/cpio.py  103-104)
             if proc.returncode:
                 raise CalledProcessError(returncode=proc.returncode, cmd=cmd)

The issue remains that we would still want to unpack the /dev/console file and other absolutes. Therefore the proper fix is to probably just use the 7z utility to unpack cpio filesystems.

I will experiment with this to determine what, if any, limitations arise when doing it this way.

gskip17 commented 1 year ago

Made a pull request for a possible solution to use 7z instead of cpio in the CpioUnpacker.

https://github.com/redballoonsecurity/ofrak/pull/276

If there is a better way to do this (eg, use the existing SevenZip component), ill leave that to reviewers.

The fix should be simple enough.

rbs-jacob commented 1 year ago

Addressed by #276.

nootkroot commented 6 months ago

Seems like this patch was reverted with #290 . I'm running into this issue now on pretty much the same setup as the original post but on the latest version (3.2.0.post0).