41

While I was playing some Capture the Flag (CTF), I couldn't solve a challenge because of this tilde ~. I'm playing on www.example.com/index.php but when I added (~) at the end: www.example.com/index.php~ , a file with name index.php started downloading.

Could you explain to me what's the role of this tilde (~)?

gerrit
  • 1,829
  • 1
  • 17
  • 26
ReDa
  • 563
  • 1
  • 4
  • 12
  • 1
    It means someone forgot to run `make clean`. – Rob Rose Mar 03 '18 at 00:42
  • Aside, URIs don't contain filenames or file extensions, they just look like they do. It's common for them to map to filesystems and serve files with matching names, but also common for them not to, e.g. `example.com/index.php~` could be a server without PHP sending content from a string, a database, etc., with a HTTP header telling the browser a filename. The fact that the downloaded file doesn't have the ~ on the end (unless that's your typo?) suggests this is more likely the case. (i.e. this is not a ~ at the end of a file extension, it's a ~ at the end of a URI). – TessellatingHeckler Mar 03 '18 at 06:44
  • 2
    For anyone interested, I believe the CTF is from root-me.org – Joe Mar 06 '18 at 17:00

4 Answers4

60

It's just part of the filename, just like letters, numbers, and other special characters can be part of the filename.

It's conventional to create "backups" of files before editing them by appending a tilde, so in case you mess something up, you have a previous version to restore. In Bash this can be easily done with cp index.php{,~} which expands to cp index.php index.php~.

It could be on the CTF because people often forget about those files and leave them unprotected. Especially a file like index.php might contain database credentials.

In bash, a tilde at the start of an argument also expands to a home folder: ~ turns into $HOME (e.g. /home/yourusername), or ~username turns into that user's home folder (e.g. ~root typically expands to /root). That is not the case here, though, because it's not at the beginning.

Luc
  • 31,973
  • 8
  • 71
  • 135
  • 12
    Some editors, e.g. `joe` uses `~` suffix for backups. – Grzegorz Oledzki Mar 01 '18 at 13:18
  • 11
    Vim does it too. – Xavier59 Mar 01 '18 at 13:48
  • 29
    Same for Gedit (plus you can actually exit it!). ;) – Andrea Lazzarotto Mar 01 '18 at 16:49
  • 6
    And emacs, because emacs. – Braiam Mar 02 '18 at 00:51
  • 1
    As far as I know, this convention originated with emacs, and tilde was chosen because it's the highest-numbered printable ASCII character, so `ls` would sort the backups after the originals (with traditional ASCII-order sorting). – zwol Mar 02 '18 at 04:17
  • 6
    @zwol: That doesn't make sense to me. If you want each backup to be immediately after the corresponding file, then you should append the *lowest*-valued character; and if you want all backups to be at the end, then you should *prepend* the highest-valued character. *Appending* the *highest*-valued character doesn't give a particularly meaningful or consistent ordering. – ruakh Mar 02 '18 at 06:41
  • 2
    @ruakh: The lowest printable ASCII character is a space. Using that in backup names would be rather funny, so to say: it's legal in UNIX and derivatives, but utterly unusable in practice. – MSalters Mar 02 '18 at 11:01
  • 2
    @MSalters : True, but you could append `!` and get it right. As it is, if you have files `foo` and `food`, the backup of `foo` will appear *after* the main `food` file. – Martin Bonner supports Monica Mar 02 '18 at 12:35
50

~ is a common suffix added to filenames for backup or temporary copies of files. This may be a manual backup or one created by an editor or other tool.

Although most file systems don't have a concept of "file extensions", a lot of software uses the part of a filename after the first or last . to determine the file type and what to do with it.

In this case, the web server will have been configured to execute files ending in .php, but to serve the contents of other file types. Since .php~ appears to be a different "file extension", it doesn't match the rule to be executed, and you are served the source code. This in turn allows you to see the likely contents of the PHP script which should have been executed (i.e. it is likely that index.php~ has similar contents to index.php), which may reveal credentials or clues to other exploits.

There are two things the hypothetical sysadmin should have done to avoid this:

  1. Not left backup files lying around inside directories mapped to web URLs.
  2. Configured the web server to respond with an error, rather than the file contents, for unrecognised file extensions.
IMSoP
  • 3,780
  • 1
  • 15
  • 19
  • 3
    That's an even better answer than mine. I completely forgot to mention that the extension change causes the vulnerability. Nice! – Luc Mar 01 '18 at 21:14
6

You've discovered a potential security flaw for web apps.

The scenario is this:

  • A web server is configured to interpret a certain file extension using a script interpreter (eg, PHP for .php files).
  • Some text editors store backup or "working" copies of the file you are editing as the same filename but with a tilde (~) on the end. A tilde often means "this is system-generated, don't worry about it".
  • These files may sometimes remain after you've finished editing, either because the editor isn't configured to remove them, or if the editor is killed without closing properly.
  • By adding a tilde to the end of a URL you may be lucky enough to stumble upon one of these backup copies that a webmaster has accidentally left (or uploaded to) their live, production site.
  • The web server won't interpret it using a script interpreter because the extension is different (eg, it's not ".php") so it drops back to its default behaviour for unknown file extensions which is to serve it as a file download.
  • You get to read the source code of their script.

Whether this is of much use is variable. Sometimes source code may contain things like authentication details for databases or external services.

thomasrutter
  • 1,465
  • 11
  • 16
  • 1
    this is a duplicate of another answer – schroeder Mar 01 '18 at 23:28
  • 2
    @thomasrutter: He didn't say it was letter-for-letter copied, he said it is a duplicate. Around here, duplicate means that you are repeating the same information without adding anything new. The exact words used to express the idea aren't important. Now, writing a new answer based in the same idea can be valuable if it is clearer, more correct, gives more background information, etc. – Ben Voigt Mar 02 '18 at 02:11
  • 5
    I only put in the effort to write an answer if I think I can explain it more clearly or provide something that additional answers couldn't, and I really did feel that I did. I'm actually offended at the accusation that I added nothing of value that wasn't already in other answers, and I disagree. It also doesn't make sense to me to complain that an answer duplicates other answers *to the same question*. Multiple answers will always cover the same ground, the differentiation is in the effort that was put in and things like how clearly it was explained, and I thought my effort reasonable. – thomasrutter Mar 02 '18 at 05:39
  • 1
    Some people answer questions without reading the other answers. I added the note to point you to the other answer in case this happened. It's a note to help you improve and differentiate the answer. I could have deleted it. Covering the same ground can happen, but you are correct that answers need to provide their own value. I'm not seeing the additional value. "Effort" doesn't count, only the outcome. Can you explain how you added additional value or said something that has separate value as the other answer? – schroeder Mar 02 '18 at 09:22
  • If you want to understand the reasoning, please post a message on [Meta](https://security.meta.stackexchange.com/) – schroeder Mar 02 '18 at 10:43
  • I decline to take part in such an exercise. I shouldn't have to go through a silly process to justify why I should be allowed to answer questions here. If what I write is as bad as you claim, it should be downvoted (as you, and only you, have done). Besides, since I wrote my answer an even more in-depth and helpful answer has appeared by Luis Casillas - had that been here I probably wouldn't have done mine. If you feel strongly about my answer being so redundant, delete it. – thomasrutter Mar 04 '18 at 22:59
3

I'm playing on www.example.com/index.php but when I added (~) at the end: www.example.com/index.php~, a file with name index.php started downloading.

As others have mentioned, many text editors (most notably Emacs, I'd say) back up earlier versions of files you work on by creating another file whose name is the same as the original but with a tilde appended.

What other answers haven't stressed enough, however, is that the fact that you can access such a file is a consequence of some mix of incorrect version control or incorrect build and deployment.

Incorrect version control (neglect of "ignore" files)

Version control systems (VCS) have mechanisms to configure a repository so that the VCS filenames that match specified patterns will be ignored. The most popular version control system today is Git, and its mechanism for this is special files named .gitignore. Most source code Git repositories ought to have a top level .gitignore file that has this line in it:

*~

That's a pattern telling Git to ignore all files whose name ends with a tilde. A common mistake among developers is to not maintain these files diligently, or just completely ignore them. For example, many IDEs will pop up a warning when they find untracked files in your source tree and give you the option of telling the IDE to ignore them. You should almost never use that option; instead, figure out what to put in the repo's "ignore" file so that everybody who checks it out automatically gets set up to never check these files in.

Disciplined use of such "ignore" files goes a very long way to protecting you from many other security problems. For example they can help protect you against the common problem of developers accidentally checking in secret credentials. One practice I've found useful is to adopt a standard layout where you projects have a designated directory for developers to place such files. You can then set up your VCS repository so files in that directory are ignored, and design your application so that development builds will get their configuration from there.

Incorrect build and deployment processes

The other thing that is likely to cause problems like that is build and deployment processes that incorrectly propagate files like the index.php~ in question.

Some practices that should be adopted to avoid this:

  • Get your version control system to ignore the files in the first place, as mentioned above.
  • Have an automated build system that periodically checks out your project from source control, builds and packages it for deployment.
  • Never edit files in the build system's work directory, so that its copy of the source repository is always clean. Always observe the discipline that developer environments are separate from automated build environments.
  • Never build releases from developers' own environments.

Another important tip is to use battle-tested build tools to build your projects, that enforce a rational project layout and have some good story on how to identify which files should be packaged and which not. The build tools for many languages, for example, instead of just blindly archiving everything in your source repository, will selectively copy files from it into a temporary staging directory, and then archive that, so that only files that the tool explicitly selected for inclusion get included.

Luis Casillas
  • 10,181
  • 2
  • 27
  • 42
  • 2
    While I agree that poor use of version control or deployment is likely to be in play, I think you've overlooked a very common scenario: *no* version control and deployment process. There are still people who develop directly on live, or install a third-party app like Wordpress and customise a couple of files, or FTP up an entire directory from a test server to a live one, etc. This feels more likely to me than the scenarios you detail here. – IMSoP Mar 06 '18 at 15:43