• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / 36ad53b4ffe99c94d658853c697647e0f252aed7

pending completion
36ad53b4ffe99c94d658853c697647e0f252aed7

push

github-actions

GitHub
Fixes for download_dir (#2151)

3739 of 6232 branches covered (60.0%)

9 of 9 new or added lines in 1 file covered. (100.0%)

12198 of 16609 relevant lines covered (73.44%)

2.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.92
/pwnlib/commandline/shellcraft.py
1
#!/usr/bin/env python2
2
from __future__ import absolute_import
3✔
3
from __future__ import division
3✔
4

5
import argparse
3✔
6
import os
3✔
7
import six
3✔
8
import sys
3✔
9
import types
3✔
10

11
import pwnlib.args
3✔
12
pwnlib.args.free_form = False
3✔
13

14
from pwn import *
3✔
15
from pwnlib.commandline import common
3✔
16

17

18
#  ____  _          _ _                 __ _
19
# / ___|| |__   ___| | | ___ _ __ __ _ / _| |_
20
# \___ \| '_ \ / _ \ | |/ __| '__/ _` | |_| __|
21
#  ___) | | | |  __/ | | (__| | | (_| |  _| |_
22
# |____/|_| |_|\___|_|_|\___|_|  \__,_|_|  \__|
23

24
def _string(s):
3✔
25
    out = []
3✔
26
    for co in bytearray(s):
3✔
27
        c = chr(co)
3✔
28
        if co >= 0x20 and co <= 0x7e and c not in '/$\'"`':
3✔
29
            out.append(c)
3✔
30
        else:
31
            out.append('\\x%02x' % co)
3✔
32
    return '"' + ''.join(out) + '"\n'
3✔
33

34

35
p = common.parser_commands.add_parser(
3✔
36
    'shellcraft',
37
    help = 'Microwave shellcode -- Easy, fast and delicious',
38
    description = 'Microwave shellcode -- Easy, fast and delicious',
39
)
40

41

42
p.add_argument(
3✔
43
    '-?', '--show',
44
    action = 'store_true',
45
    help = 'Show shellcode documentation',
46
)
47

48
p.add_argument(
3✔
49
    '-o', '--out',
50
    metavar = 'file',
51
    type = argparse.FileType('wb'),
52
    default = getattr(sys.stdout, 'buffer', sys.stdout),
53
    help = 'Output file (default: stdout)',
54
)
55

56
p.add_argument(
3✔
57
    '-f', '--format',
58
    metavar = 'format',
59
    choices = ['r', 'raw',
60
               's', 'str', 'string',
61
               'c',
62
               'h', 'hex',
63
               'a', 'asm', 'assembly',
64
               'p',
65
               'i', 'hexii',
66
               'e', 'elf',
67
               'd', 'escaped',
68
               'default'],
69
    default = 'default',
70
    help = 'Output format (default: hex), choose from {e}lf, {r}aw, {s}tring, {c}-style array, {h}ex string, hex{i}i, {a}ssembly code, {p}reprocssed code, escape{d} hex string',
71
)
72

73
p.add_argument(
3✔
74
    'shellcode',
75
    nargs = '?',
76
    help = 'The shellcode you want',
77
    type = str
78
)
79

80
p.add_argument(
3✔
81
    'args',
82
    nargs = '*',
83
    metavar = 'arg',
84
    default = (),
85
    help = 'Argument to the chosen shellcode',
86
)
87

88
p.add_argument(
3✔
89
    '-d',
90
    '--debug',
91
    help='Debug the shellcode with GDB',
92
    action='store_true'
93
)
94

95
p.add_argument(
3✔
96
    '-b',
97
    '--before',
98
    help='Insert a debug trap before the code',
99
    action='store_true'
100
)
101

102
p.add_argument(
3✔
103
    '-a',
104
    '--after',
105
    help='Insert a debug trap after the code',
106
    action='store_true'
107
)
108

109
p.add_argument(
3✔
110
    '-v', '--avoid',
111
    action='append',
112
    help = 'Encode the shellcode to avoid the listed bytes'
113
)
114

115
p.add_argument(
3✔
116
    '-n', '--newline',
117
    dest='avoid',
118
    action='append_const',
119
    const='\n',
120
    help = 'Encode the shellcode to avoid newlines'
121
)
122

123
p.add_argument(
3✔
124
    '-z', '--zero',
125
    dest='avoid',
126
    action='append_const',
127
    const='\x00',
128
    help = 'Encode the shellcode to avoid NULL bytes'
129
)
130

131
p.add_argument(
3✔
132
    '-r',
133
    '--run',
134
    help="Run output",
135
    action='store_true'
136
)
137

138
p.add_argument(
3✔
139
    '--color',
140
    help="Color output",
141
    action='store_true',
142
    default=sys.stdout.isatty()
143
)
144

145
p.add_argument(
3✔
146
    '--no-color',
147
    help="Disable color output",
148
    action='store_false',
149
    dest='color'
150
)
151

152
p.add_argument(
3✔
153
    '--syscalls',
154
    help="List syscalls",
155
    action='store_true'
156
)
157

158
p.add_argument(
3✔
159
    '--address',
160
    help="Load address",
161
    default=None
162
)
163

164
p.add_argument(
3✔
165
    '-l', '--list',
166
    action='store_true',
167
    help='List available shellcodes, optionally provide a filter'
168
)
169

170
p.add_argument(
3✔
171
    '-s', '--shared',
172
    action='store_true',
173
    help='Generated ELF is a shared library'
174
)
175

176
def get_template(name):
3✔
177
    func = shellcraft
3✔
178
    for attr in name.split('.'):
3✔
179
        func = getattr(func, attr)
3✔
180
    return func
3✔
181

182
def is_not_a_syscall_template(name):
3✔
183
    template_src = shellcraft._get_source(name)
3✔
184
    return '/syscalls' not in template_src
3✔
185

186
def main(args):
3✔
187
    if args.list:
3✔
188
        templates = shellcraft.templates
3✔
189

190
        if args.shellcode:
3✔
191
            templates = filter(lambda a: args.shellcode in a, templates)
3✔
192
        elif not args.syscalls:
3✔
193
            templates = filter(is_not_a_syscall_template, templates)
3✔
194

195
        print('\n'.join(templates))
3✔
196
        exit()
3✔
197

198
    if not args.shellcode:
3!
199
        common.parser.print_usage()
×
200
        exit()
×
201

202
    try:
3✔
203
        func = get_template(args.shellcode)
3✔
204
    except AttributeError:
×
205
        log.error("Unknown shellcraft template %r. Use --list to see available shellcodes." % args.shellcode)
×
206

207
    if args.show:
3✔
208
        # remove doctests
209
        doc = []
3✔
210
        in_doctest = False
3✔
211
        block_indent = None
3✔
212
        caption = None
3✔
213
        lines = func.__doc__.splitlines()
3✔
214
        i = 0
3✔
215
        while i < len(lines):
3✔
216
            line = lines[i]
3✔
217
            if line.lstrip().startswith('>>>'):
3✔
218
                # this line starts a doctest
219
                in_doctest = True
3✔
220
                block_indent = None
3✔
221
                if caption:
3✔
222
                    # delete back up to the caption
223
                    doc = doc[:caption - i]
3✔
224
                    caption = None
3✔
225
            elif line == '':
3✔
226
                # skip blank lines
227
                pass
3✔
228
            elif in_doctest:
3✔
229
                # indentation marks the end of a doctest
230
                indent = len(line) - len(line.lstrip())
3✔
231
                if block_indent is None:
3!
232
                    if not line.lstrip().startswith('...'):
3!
233
                        block_indent = indent
3✔
234
                elif indent < block_indent:
×
235
                    in_doctest = False
×
236
                    block_indent = None
×
237
                    # re-evalutate this line
238
                    continue
×
239
            elif line.endswith(':'):
3✔
240
                # save index of caption
241
                caption = i
3✔
242
            else:
243
                # this is not blank space and we're not in a doctest, so the
244
                # previous caption (if any) was not for a doctest
245
                caption = None
3✔
246

247
            if not in_doctest:
3✔
248
                doc.append(line)
3✔
249
            i += 1
3✔
250
        print('\n'.join(doc).rstrip())
3✔
251
        exit()
3✔
252

253
    defargs = len(six.get_function_defaults(func) or ())
3✔
254
    reqargs = six.get_function_code(func).co_argcount - defargs
3✔
255
    if len(args.args) < reqargs:
3!
256
        if defargs > 0:
×
257
            log.critical('%s takes at least %d arguments' % (args.shellcode, reqargs))
×
258
            sys.exit(1)
×
259
        else:
260
            log.critical('%s takes exactly %d arguments' % (args.shellcode, reqargs))
×
261
            sys.exit(1)
×
262

263
    # Captain uglyness saves the day!
264
    for i, val in enumerate(args.args):
3✔
265
        try:
3✔
266
            args.args[i] = util.safeeval.expr(val)
3✔
267
        except ValueError:
3✔
268
            pass
3✔
269

270
    # And he strikes again!
271
    list(map(common.context_arg, args.shellcode.split('.')))
3✔
272
    code = func(*args.args)
3✔
273

274

275
    if args.before:
3✔
276
        code = shellcraft.trap() + code
3✔
277
    if args.after:
3✔
278
        code = code + shellcraft.trap()
3✔
279

280

281
    if args.format in ['a', 'asm', 'assembly']:
3✔
282
        if args.color:
3!
283
            from pygments import highlight
3✔
284
            from pygments.formatters import TerminalFormatter
3✔
285
            from pwnlib.lexer import PwntoolsLexer
3✔
286

287
            code = highlight(code, PwntoolsLexer(), TerminalFormatter())
3✔
288

289
        print(code)
3✔
290
        exit()
3✔
291
    if args.format == 'p':
3✔
292
        print(cpp(code))
3✔
293
        exit()
3✔
294

295
    assembly = code
3✔
296

297
    vma = args.address
3✔
298
    if vma:
3!
299
        vma = pwnlib.util.safeeval.expr(vma)
×
300

301
    if args.format in ['e','elf']:
3✔
302
        args.format = 'default'
3✔
303
        try: os.fchmod(args.out.fileno(), 0o700)
3✔
304
        except OSError: pass
3✔
305

306

307
        if not args.avoid:
3!
308
            code = read(make_elf_from_assembly(assembly, vma=vma, shared=args.shared))
3✔
309
        else:
310
            code = asm(assembly)
×
311
            code = encode(code, args.avoid)
×
312
            code = make_elf(code, vma=vma, shared=args.shared)
×
313
            # code = read(make_elf(encode(asm(code), args.avoid)))
314
    else:
315
        code = encode(asm(assembly), args.avoid)
3✔
316

317
    if args.format == 'default':
3✔
318
        if args.out.isatty():
3!
319
            args.format = 'hex'
×
320
        else:
321
            args.format = 'raw'
3✔
322

323
    arch = args.shellcode.split('.')[0]
3✔
324

325
    if args.debug:
3!
326
        if not args.avoid:
×
327
            proc = gdb.debug_assembly(assembly, arch=arch, vma=vma)
×
328
        else:
329
            proc = gdb.debug_shellcode(code, arch=arch, vma=vma)
×
330
        proc.interactive()
×
331
        sys.exit(0)
×
332

333
    if args.run:
3✔
334
        proc = run_shellcode(code, arch=arch)
3✔
335
        proc.interactive()
3✔
336
        sys.exit(0)
3✔
337

338
    if args.format in ['s', 'str', 'string']:
3✔
339
        code = _string(code)
3✔
340
    elif args.format == 'c':
3✔
341
        code = '{' + ', '.join(map(hex, bytearray(code))) + '}' + '\n'
3✔
342
    elif args.format in ['h', 'hex']:
3!
343
        code = pwnlib.util.fiddling.enhex(code) + '\n'
×
344
    elif args.format in ['i', 'hexii']:
3✔
345
        code = hexii(code) + '\n'
3✔
346
    elif args.format in ['d', 'escaped']:
3!
347
        code = ''.join('\\x%02x' % c for c in bytearray(code)) + '\n'
×
348
    if not sys.stdin.isatty():
3!
349
        args.out.write(getattr(sys.stdin, 'buffer', sys.stdin).read())
3✔
350

351
    if not hasattr(code, 'decode'):
3!
352
        code = code.encode()
×
353
    args.out.write(code)
3✔
354

355
if __name__ == '__main__':
3✔
356
    pwnlib.commandline.common.main(__file__)
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc