Last active
August 23, 2025 11:19
-
-
Save bahorn/624596bbe235bffadb2b578d605f5cf5 to your computer and use it in GitHub Desktop.
file2cmdline.py - store an arbitary file in /proc/self/cmdline and expose it to the rest of the system
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
file2cmdline.py - bah / august 2025 - MIT license | |
a very stupid trick to create a tmpfile without memfd or the other usual | |
approaches. | |
essentially just storing it in the /proc/PID/cmdline of a sacrificial process. | |
cat works well for this as it doesn't die instantly if it hits an non existant | |
file, and you can stall it if it sees a blocking file like /dev/stdout | |
abusing the filename to store code is a pretty well known trick, see all 9000 | |
BGGP5 entries using it, but i've not seen anything about using it as a method of | |
getting an in-mem tempfile on systems without any writable filesystems. | |
what you might want this for is a undecided, maybe not bad for hitting more bugs | |
in userspace tools if you wanna get native code exec that way. | |
but you should just use python / perl to make a memfd, and load a shared object | |
from the memfd with a lolbin. | |
its way easier, and if you unmap() it and do a sleep mask you'll have no obvious | |
artifacts left in /proc/PID/maps. | |
sadly can't be mmap()'d, like most things in /proc/PID, so not possible to load | |
shared objects via this. | |
can fully write nullbytes via empty arguments and $'\n' lets you do whatever you | |
want with newlines. | |
""" | |
import argparse | |
import base64 | |
def convert(b): | |
if b == b'': | |
return "''" | |
return f'${repr(bytes(b))[1:]}' | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('filename') | |
parser.add_argument('--shell', default='bash') | |
args = parser.parse_args() | |
shell = args.shell | |
blocks = [] | |
b = b'' | |
with open(args.filename, 'rb') as f: | |
b = f.read() | |
curr = bytearray() | |
last = False | |
for c in b: | |
last = False | |
if int(c) != 0: | |
curr.append(c) | |
else: | |
blocks.append(curr) | |
curr = bytearray() | |
last = True | |
if not last: | |
blocks.append(curr) | |
argv0 = convert(blocks[0]) | |
args = ' '.join([convert(block) for block in blocks[1:]]) | |
print(f'#!/usr/bin/{shell}') | |
print(f'exec -a {argv0} -- cat {args}') | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment