Is there an alternative for the slash in a path? - linux

I have an application which correctly escapes slashes ("/) in file names to avoid path traversal attacks.
The secret file has this path:
/tmp/secret.txt
I want to access this file by uploading a file with a special crafted file name (something like \/tmp\/secret.txt)
Is there any alternative syntax without the slashes which I can use so that Linux will read this file?
(I'm aware of URL encoding but as the escaping is done in the backend this has no use for me.)

No. The / is not allowed in a filename, no matter if it's escaped as \/ or not.
It is one out of only two characters that are not allowed in filenames, the other being \0.
This means that you obviously could use _tmp_secret.txt or -tmp-secret.txt, or replace the / in the path with any other character that you wish, to create a filename with a path "encoded into it". But in doing so, you can not encode pathnames that includes the chosen delimiter character in one or several of its path components and expect to decode it into the original pathname.
This is, by the way, how OpenBSD's ports system encodes filenames for patches to software. In (for example) /usr/ports/shells/fish/patches we find files with names like
patch-share_tools_create_manpage_completions_py
which comes from the pathname of a particular file in the fish shell source distribution (probably share/tools/create_manpage_completions.py). These pathnames are however never parsed, and the encoding is only there to create unique and somewhat intelligible filenames for the patches themselves. The real paths are included in the patch files.

Related

Why does Rust output escape backslashes on paths in windows? What is best way to remove the extra backslashes from output?

Background
Writing a program that watches a directory and subdirs and alerts user when file(s) in the path are created, updated, edited. Code is shared on github.
I'm new to Rust (about 1 week of experience).
Make Output Path Easy to Use
I want user to be able to easily copy the output path (see pic below) and copy / paste it for use.
When I run the program on Linux it works great with directory separators (/ - forward slash) and the user can easily copy the path and use it.
Problem : Windows Platform Uses Backslashes
The problem is that on Windows platform paths are separated by backslashes (which are also escape chars).
Double-Backslashes
When the program outputs the path on Windows it always shows double backslashes and the path isn't easily copy-able.
Here's a snapshot of the output:
As an example I am using the following output:
println!("{:?}", Path::new("c:\\windows\\"));
The output is from the Path::new() method itself, but it always outputs the path string with the double backslashes.
Can you help me find a better way to format the output so that it has single backslashes like a normal path (which excludes the escape backslashes)?
EDIT
Someone mentioned trying raw string input so I tried the following:
println!("{:?}", Path::new(r"c:\windows\"));
However, the Path::new method still outputs double backslashes.
The Problem is that you are using the Debug formatting to print the path, this causes characters that would need to be escaped in a string literal to be escaped in the output.
Instead you should use the normal Display formatting, though as Path does not directly implement Display you will need to call display on the path to display it.
println!("{}", Path::new("c:\\windows\\").display());
Note that Path::display is not loss-less in case the path contains non-unicode data.

Copy zip file and unzip using puppet in windows 10

I'm trying to copy one file using puppet in windows.
Code is as below :-
file { 'D:\mycopy\folder\filename':
ensure => present,
mode => '0660',
source => "d:\temp\test.zip",
}
It is giving me below error
Cannot use opaque urls' file:\d: est\test.zip
I want to unzip also after copy. Thanks.
Puppet recognizes both backslashes (\) and forward slashes (/) as path separators in Windows file names. Although Windows shells want the former, the latter is a lot safer to use in Puppet manifests.
In this case, the two appearances of \t in your double-quoted path string will be interpreted as escape sequences representing the tab character. You could solve that issue in this case by doubling the backslashes, by switching to a single-quoted string, or by switching to forward slashes. As a matter of style, I would both switch to single quotes (because there are no variable interpolations or single quotes in the string content) and switch to forward slashes:
However, the actual diagnostic about opaque URLs is a clue to another issue: Puppet accepts URLs as values of File's source parameter, and it is interpreting your absolute filename as a URL with scheme 'd'. To work around this, you should express the source via a file: URL:
source => 'file://d:/temp/test.zip'

rename command for replacing text in filename from a certain point (character), but only up to, and maintaining the file extension

I've got a ton of files as follows
audiofile_drums_1-ktpcwybsh5c.wav
soundsample_drums_2-fghlkjy57sa.wav
noise_snippet_guitar_5-mxjtgqta3o1.wav
louder_flute_9-mdlsiqpfj6c.wav
I want to remove everything between and including the "-" and the .wav file extension, to be left with
audiofile_drums_1.wav
soundsample_drums_2.wav
noise_snippet_guitar_5.wav
louder_flute_9.wav
I've tried to do delete everything following and including the character "-" using
rename 's/-.*//' *
Which gives me
audiofile_drums_1
soundsample_drums_2
noise_snippet_guitar_5
louder_flute_9
And for lack of finding an easy way to rename all the files again, adding .wav the extension, I am hoping there is a slicker way to do this in one nifty command in one stage instead of 2.
Any suggestions?
Thanks
You can use rename 's/-[^\.]*\.wav$/\.wav/' *
The first part -[^\.]*\.wav$ searchs for a - followed by n chars that are not . followed by .wav and the end of filename. The end of filename and .wav is not strictly needed but it helps avoid renaming files you don't want to rename.
The /\.wav/ preserves the extension.
Please not that rename is not a standard utility, and is part of perl, so rename may not be available on every linux system.
This works in my specific case, but should work for any file extension.
rename -n 's/-.*(?=\.wav$)//' *
The command looks for all characters after and inclusive of the - symbol in the filename, then, using a positive lookahead** (?=\.wav$) to search for the characters (the file extension in this case) at the end of the filename (denoted by $, and replaces them with no characters (removing them).
** NOTE: A positive look ahead is a zero width assertion.
It will affect the match but it will not be included
in the replacement. (The '.wav' part will not be
erased)
In this example (?=\.wav$) is the positive lookahead. The dollar sign $, as in regex, denotes at the end of the line, so perfect for a file extension.

How to add file to .gitignore with \n in the filename

I just want to add file with file
name (file name contains \n) to .gitignore.
I try:
/file
name
/file\nname
file\
name
but have no luck.
Try
/file*name
* should match any characters.
Please tell me this is a homework assignment.
The .gitignore file uses a glob(7) style wildcard substitution so embedding a '*' should work. Linux really doesn't care about the filename spelling, so any character other than a '/' can go into a filename. On a command line be sure to use single-quotes (not double-quotes, mind you) so the shell doesn't get confused.
Reading the filenames from ls(1) and similar will split the name at the \n character because the glibc standard library is looking for newlines to find the end of a line of text. The '/' and '\n' characters are treated specially in many levels of the software stack, like the pathname of the file or splitting a buffer into lines or displaying the filename or letting awk(1), sed(1), and such scan a list of filenames.
But I agree with another poster: this is a bad idea. No, I take that back, it's a horrible idea. Long-term maintainability is going to be a nightmare.

Are /../ and /./ the only file system symbolic links?

I want to check that a file system path is valid and safe to use relative to another path. So I want to know if there are any other special characters like /../ and /./ which might cause a path to actually point somewhere else.
If that is all I have to worry about then a quick replace of those chars followed by something like this to check for any other bad filesystem chars should work right?
[^a-z0-9\.\-_]
(On windows stuff like C:\ would also have to be allowed)
The use case is that I have a folder which site administrators can create directories in and I want to FORCE them to only create directories in that folder. In other words, no being sneaky with ...path/uploads/../../../var/otherfolder/ if you know what I mean ;)
Which language are you using?
In PHP, for example, you can get the realpath of any string and then compare it to a base directory. If you find your base directoy is a prefix of the realpath, then you're good to go.
Although that's only for PHP, you should be able to find a similar approach in other languages.
There are several oddities on Windows/DOS. Opening any of these will both read and write to unexpected places. I havnt tried how .NET handles these, but I presume that you would get some kind of security exceptions.
CON Console. Reads from keyboard, writes to screen.
"COPY CON temp.txt", end input with ctrl-z.
PRN Printer. (Defaults to LPT1?)
LPTn Parallell ports.
AUX "Auxiliary device." Have never seen anyone use this myself.
COMn Serial ports.
NUL /dev/null
For resolving paths, ., and .., (and in most cases, // for Unix and \\ for Windows) are the main things you really need to worry about in terms of resolving paths. From RFC 3986, this is the algorithm for resolving relative paths in URIs. For the most part, it also applies to file system paths.
An algorithm, remove_dot_segments:
The input buffer is initialized with the now-appended path
components and the output buffer is initialized to the empty
string.
While the input buffer is not empty, loop as follows:
If the input buffer begins with a prefix of "../" or "./",
then remove that prefix from the input buffer; otherwise,
If the input buffer begins with a prefix of "/./" or "/.",
where "." is a complete path segment, then replace that
prefix with "/" in the input buffer; otherwise,
If the input buffer begins with a prefix of "/../" or "/..",
where ".." is a complete path segment, then replace that
prefix with "/" in the input buffer and remove the last
segment and its preceding "/" (if any) from the output
buffer; otherwise,
If the input buffer consists only of "." or "..", then remove
that from the input buffer; otherwise,
Move the first path segment in the input buffer to the end of
the output buffer, including the initial "/" character (if
any) and any subsequent characters up to, but not including,
the next "/" character or the end of the input buffer.
Finally, the output buffer is returned as the result of
remove_dot_segments.
Example run:
STEP OUTPUT BUFFER INPUT BUFFER
1 : /a/b/c/./../../g
2E: /a /b/c/./../../g
2E: /a/b /c/./../../g
2E: /a/b/c /./../../g
2B: /a/b/c /../../g
2C: /a/b /../g
2C: /a /g
2E: /a/g
STEP OUTPUT BUFFER INPUT BUFFER
1 : mid/content=5/../6
2E: mid /content=5/../6
2E: mid/content=5 /../6
2C: mid /6
2E: mid/6
Don't forget that it's possible to do things like specify more ".." segments than there are parent directories. So if you're trying to resolve a path, you could end up trying to resolve beyond /, or in the case of Windows, C:\.
The answer depends on the filesystem used. It's different on Windows, different on *nix.
For example, on Windows-based desktop platforms, invalid path characters might include quote ("), less than (<), greater than (>), pipe (|), backspace (\b), null (\0), and Unicode characters 16 through 18 and 20 through 25.
I don't know which platform/language are you using, but if you are using .NET you can get list of chars which cannot be in filename by calling Path.GetInvalidFilenameChars and list of chars which cannot be in path by calling Path.GetInvalidPathChars
Unix symbolic links can be tricky, and can even be created to cause pathing loops on some systems. You should lstat() the filename to get the actual inode and devno numbers to see if two pathnames are actually the same file.
Have you considered using something like chroot? You can create something called a "chroot jail" that will prevent people from getting outside it. This is enforced by the OS, so you don't have to write it yourself. Note that this only works on *nix, and on some variants of *nix, it does not have all the security features necessary to make it foolproof (i.e. there are known ways of escaping).
I've already directly answered the question, but as Tom said, what you're trying to do is inherently dangerous. What you should probably do instead is create one directory at a time. Pass it through a regexp validator and don't let them use dot segments at all. Just have a text field in a form for the directory name and a "Make Directory" button. Let them traverse the directory tree to create sub-directories. This way you can be absolutely confident that the files are going where they should.
This has the advantage of working on both Windows and *nix without the need for chroot.
Addenda:
This Regexp will only match illegitimate directory names, assuming that you're accepting directories one at a time:
/^(\.\.?|.*?[^a-zA-Z0-9\. _-]+.*?|^)$/
Valid directory names:
"This is a directory"
".hidden"
"example.com"
"10-28-2009"
Invalid directory names:
""
"."
".."
"../somewhere/else"
"/etc/passwd"
"would:be?rejected!by;OS"

Resources