diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 145b668e4..a3f2fa694 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -150,11 +150,18 @@ jobs: pwn shellcraft --list |tail pwn shellcraft -l --syscalls |tail pwn shellcraft -l execve + pwn shellcraft -l execve + exit pwn shellcraft --show i386.linux.loader_append + pwn shellcraft --show i386.linux.loader_append + i386.linux.sh pwn shellcraft -f asm --color amd64.linux.sh + pwn shellcraft -f asm --color amd64.linux.setreuid + amd64.linux.cat /etc/passwd + pwn shellcraft -f asm --color amd64.linux.setreuid = amd64.linux.cat /key+secret --delim = pwn shellcraft -f elf amd64.linux.syscalls.exit 0 1: + args = shellcode[1:] + for attr in cur_name.split('.'): + func = getattr(func, attr) + funcs.append((cur_name, func, args)) + return funcs def is_not_a_syscall_template(name): template_src = shellcraft._get_source(name) return '/syscalls' not in template_src def main(args): + delim = '+' + if args.delim: + delim = args.delim.strip() + + shellcodes = [] + if args.shellcode: + current = [] + for s in args.shellcode: + if s.strip() == delim: + shellcodes.append(current) + current = [] + else: + current.append(s) + if len(current) > 0: + shellcodes.append(current) + if args.list: templates = shellcraft.templates if args.shellcode: - templates = filter(lambda a: args.shellcode in a, templates) + template_array = [] + for s in shellcodes: + template_array.extend(list(filter(lambda a: s[0] in a, templates))) + templates = template_array elif not args.syscalls: - templates = filter(is_not_a_syscall_template, templates) + templates = list(filter(is_not_a_syscall_template, templates)) print('\n'.join(templates)) exit() @@ -199,84 +223,92 @@ def main(args): exit() try: - func = get_template(args.shellcode) + funcs = get_template(shellcodes) except AttributeError: log.error("Unknown shellcraft template %r. Use --list to see available shellcodes." % args.shellcode) if args.show: - # remove doctests - doc = [] - in_doctest = False - block_indent = None - caption = None - lines = func.__doc__.splitlines() - i = 0 - while i < len(lines): - line = lines[i] - if line.lstrip().startswith('>>>'): - # this line starts a doctest - in_doctest = True - block_indent = None - if caption: - # delete back up to the caption - doc = doc[:caption - i] - caption = None - elif line == '': - # skip blank lines - pass - elif in_doctest: - # indentation marks the end of a doctest - indent = len(line) - len(line.lstrip()) - if block_indent is None: - if not line.lstrip().startswith('...'): - block_indent = indent - elif indent < block_indent: - in_doctest = False + for (name, func, _args) in funcs: + # remove doctests + doc = [] + in_doctest = False + block_indent = None + caption = None + lines = func.__doc__.splitlines() + i = 0 + if len(funcs) > 1: + print('%s:' % name) + while i < len(lines): + line = lines[i] + if line.lstrip().startswith('>>>'): + # this line starts a doctest + in_doctest = True block_indent = None - # re-evalutate this line - continue - elif line.endswith(':'): - # save index of caption - caption = i - else: - # this is not blank space and we're not in a doctest, so the - # previous caption (if any) was not for a doctest - caption = None - - if not in_doctest: - doc.append(line) - i += 1 - print('\n'.join(doc).rstrip()) + if caption: + # delete back up to the caption + doc = doc[:caption - i] + caption = None + elif line == '': + # skip blank lines + pass + elif in_doctest: + # indentation marks the end of a doctest + indent = len(line) - len(line.lstrip()) + if block_indent is None: + if not line.lstrip().startswith('...'): + block_indent = indent + elif indent < block_indent: + in_doctest = False + block_indent = None + # re-evalutate this line + continue + elif line.endswith(':'): + # save index of caption + caption = i + else: + # this is not blank space and we're not in a doctest, so the + # previous caption (if any) was not for a doctest + caption = None + + if not in_doctest: + doc.append(line) + i += 1 + print('\n'.join(doc).rstrip()) + if len(funcs) > 1: + print('') exit() - defargs = len(six.get_function_defaults(func) or ()) - reqargs = six.get_function_code(func).co_argcount - defargs - if len(args.args) < reqargs: - if defargs > 0: - log.critical('%s takes at least %d arguments' % (args.shellcode, reqargs)) - sys.exit(1) - else: - log.critical('%s takes exactly %d arguments' % (args.shellcode, reqargs)) - sys.exit(1) + code_array = [] + for (name, func, func_args) in funcs: + defargs = len(six.get_function_defaults(func) or ()) + reqargs = six.get_function_code(func).co_argcount - defargs - # Captain uglyness saves the day! - for i, val in enumerate(args.args): - try: - args.args[i] = util.safeeval.expr(val) - except ValueError: - pass + if len(func_args) < reqargs: + if defargs > 0: + log.critical('%s takes at least %d arguments' % (name, reqargs)) + sys.exit(1) + else: + log.critical('%s takes exactly %d arguments' % (name, reqargs)) + sys.exit(1) + + # Captain uglyness saves the day! + for i, val in enumerate(func_args): + try: + func_args[i] = util.safeeval.expr(val) + except ValueError: + pass - # And he strikes again! - list(map(common.context_arg, args.shellcode.split('.'))) - code = func(*args.args) + # And he strikes again! + list(map(common.context_arg, name.split('.'))) + code_array.append(func(*func_args)) + code = "".join(code_array) if args.before: code = shellcraft.trap() + code if args.after: code = code + shellcraft.trap() - if args.format in ['a', 'asm', 'assembly']: if args.color: from pygments import highlight @@ -319,7 +351,7 @@ def main(args): else: args.format = 'raw' - arch = args.shellcode.split('.')[0] + arch = name.split('.')[0] if args.debug: if not args.avoid: